|
8 | 8 | // option. This file may not be copied, modified, or distributed |
9 | 9 | // except according to those terms. |
10 | 10 |
|
| 11 | +use std::borrow::Cow; |
| 12 | + |
11 | 13 | use rustc::mir; |
12 | 14 | use rustc::ty::{self, Ty}; |
13 | 15 | use rustc::ty::layout::LayoutOf; |
@@ -335,84 +337,76 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { |
335 | 337 | // Figure out how to pass which arguments. |
336 | 338 | // FIXME: Somehow this is horribly full of special cases here, and codegen has |
337 | 339 | // none of that. What is going on? |
338 | | - trace!("ABI: {:?}", sig.abi); |
339 | 340 | trace!( |
340 | | - "args: {:#?}", |
| 341 | + "ABI: {:?}, args: {:#?}", |
| 342 | + sig.abi, |
341 | 343 | args.iter() |
342 | 344 | .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) |
343 | 345 | .collect::<Vec<_>>() |
344 | 346 | ); |
345 | 347 | trace!( |
346 | | - "locals: {:#?}", |
| 348 | + "spread_arg: {:?}, locals: {:#?}", |
| 349 | + mir.spread_arg, |
347 | 350 | mir.args_iter() |
348 | 351 | .map(|local| |
349 | 352 | (local, self.layout_of_local(self.cur_frame(), local).unwrap().ty) |
350 | 353 | ) |
351 | 354 | .collect::<Vec<_>>() |
352 | 355 | ); |
353 | | - match instance.def { |
354 | | - ty::InstanceDef::ClosureOnceShim { .. } if sig.abi == Abi::Rust => { |
355 | | - // this has an entirely ridicolous calling convention where it uses the |
356 | | - // "Rust" ABI, but arguments come in untupled and are supposed to be tupled |
357 | | - // for the callee! The function's first argument is a ZST, and then |
358 | | - // there comes a tuple for the rest. |
359 | | - let mut arg_locals = mir.args_iter(); |
360 | | - |
361 | | - { // the ZST. nothing to write. |
362 | | - let arg_local = arg_locals.next().unwrap(); |
363 | | - let dest = self.eval_place(&mir::Place::Local(arg_local))?; |
364 | | - assert!(dest.layout.is_zst()); |
365 | | - } |
366 | 356 |
|
367 | | - { // the tuple argument. |
368 | | - let arg_local = arg_locals.next().unwrap(); |
369 | | - let dest = self.eval_place(&mir::Place::Local(arg_local))?; |
370 | | - assert_eq!(dest.layout.fields.count(), args.len()); |
371 | | - for (i, &op) in args.iter().enumerate() { |
372 | | - let dest_field = self.place_field(dest, i as u64)?; |
373 | | - self.copy_op(op, dest_field)?; |
374 | | - } |
375 | | - } |
| 357 | + // We have two iterators: Where the arguments come from, |
| 358 | + // and where they go to. |
| 359 | + |
| 360 | + // For where they come from: If the ABI is RustCall, we untuple the |
| 361 | + // last incoming argument. These do not have the same type, |
| 362 | + // so to keep the code paths uniform we accept an allocation |
| 363 | + // (for RustCall ABI only). |
| 364 | + let args_effective : Cow<[OpTy<'tcx>]> = |
| 365 | + if sig.abi == Abi::RustCall && !args.is_empty() { |
| 366 | + // Untuple |
| 367 | + let (&untuple_arg, args) = args.split_last().unwrap(); |
| 368 | + trace!("eval_fn_call: Will pass last argument by untupling"); |
| 369 | + Cow::from(args.iter().map(|&a| Ok(a)) |
| 370 | + .chain((0..untuple_arg.layout.fields.count()).into_iter() |
| 371 | + .map(|i| self.operand_field(untuple_arg, i as u64)) |
| 372 | + ) |
| 373 | + .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?) |
| 374 | + } else { |
| 375 | + // Plain arg passing |
| 376 | + Cow::from(args) |
| 377 | + }; |
376 | 378 |
|
377 | | - // that should be it |
378 | | - assert!(arg_locals.next().is_none()); |
| 379 | + // Now we have to spread them out across the callee's locals, |
| 380 | + // taking into account the `spread_arg`. |
| 381 | + let mut args_iter = args_effective.iter(); |
| 382 | + let mut local_iter = mir.args_iter(); |
| 383 | + // HACK: ClosureOnceShim calls something that expects a ZST as |
| 384 | + // first argument, but the callers do not actually pass that ZST. |
| 385 | + // Codegen doesn't care because ZST arguments do not even exist there. |
| 386 | + match instance.def { |
| 387 | + ty::InstanceDef::ClosureOnceShim { .. } if sig.abi == Abi::Rust => { |
| 388 | + let local = local_iter.next().unwrap(); |
| 389 | + let dest = self.eval_place(&mir::Place::Local(local))?; |
| 390 | + assert!(dest.layout.is_zst()); |
379 | 391 | } |
380 | | - _ => { |
381 | | - // overloaded-calls-simple.rs in miri's test suite demomstrates that there is |
382 | | - // no way to predict, from the ABI and instance.def, whether the function |
383 | | - // wants arguments passed with untupling or not. So we just make it |
384 | | - // depend on the number of arguments... |
385 | | - let untuple = |
386 | | - sig.abi == Abi::RustCall && !args.is_empty() && args.len() != mir.arg_count; |
387 | | - let (normal_args, untuple_arg) = if untuple { |
388 | | - let (tup, args) = args.split_last().unwrap(); |
389 | | - trace!("eval_fn_call: Will pass last argument by untupling"); |
390 | | - (args, Some(tup)) |
391 | | - } else { |
392 | | - (&args[..], None) |
393 | | - }; |
394 | | - |
395 | | - // Pass the arguments. |
396 | | - let mut arg_locals = mir.args_iter(); |
397 | | - // First the normal ones. |
398 | | - for &op in normal_args { |
399 | | - let arg_local = arg_locals.next().unwrap(); |
400 | | - let dest = self.eval_place(&mir::Place::Local(arg_local))?; |
401 | | - self.copy_op(op, dest)?; |
402 | | - } |
403 | | - // The the ones to untuple. |
404 | | - if let Some(&untuple_arg) = untuple_arg { |
405 | | - for i in 0..untuple_arg.layout.fields.count() { |
406 | | - let arg_local = arg_locals.next().unwrap(); |
407 | | - let dest = self.eval_place(&mir::Place::Local(arg_local))?; |
408 | | - let op = self.operand_field(untuple_arg, i as u64)?; |
409 | | - self.copy_op(op, dest)?; |
410 | | - } |
| 392 | + _ => {} |
| 393 | + } |
| 394 | + // Now back to norml argument passing. |
| 395 | + while let Some(local) = local_iter.next() { |
| 396 | + let dest = self.eval_place(&mir::Place::Local(local))?; |
| 397 | + if Some(local) == mir.spread_arg { |
| 398 | + // Must be a tuple |
| 399 | + for i in 0..dest.layout.fields.count() { |
| 400 | + let dest = self.place_field(dest, i as u64)?; |
| 401 | + self.copy_op(*args_iter.next().unwrap(), dest)?; |
411 | 402 | } |
412 | | - // That should be it. |
413 | | - assert!(arg_locals.next().is_none()); |
| 403 | + } else { |
| 404 | + // Normal argument |
| 405 | + self.copy_op(*args_iter.next().unwrap(), dest)?; |
414 | 406 | } |
415 | 407 | } |
| 408 | + // Now we should be done |
| 409 | + assert!(args_iter.next().is_none()); |
416 | 410 | Ok(()) |
417 | 411 | } |
418 | 412 | // cannot use the shim here, because that will only result in infinite recursion |
|
0 commit comments