use syntax::source_map::Span;
use rustc_target::spec::abi::Abi;
-use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
+use rustc::mir::interpret::{EvalResult, PointerArithmetic, InterpError, Scalar};
use super::{
InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
};
self.goto_block(Some(target))?;
} else {
// Compute error message
- use rustc::mir::interpret::EvalErrorKind::*;
+ use rustc::mir::interpret::InterpError::*;
return match *msg {
BoundsCheck { ref len, ref index } => {
let len = self.read_immediate(self.eval_operand(len, None)?)
return Ok(());
}
let caller_arg = caller_arg.next()
- .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
+ .ok_or_else(|| InterpError::FunctionArgCountMismatch)?;
if rust_abi {
debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
}
);
// Figure out how to pass which arguments.
- // We have two iterators: Where the arguments come from,
- // and where they go to.
+ // The Rust ABI is special: ZST get skipped.
let rust_abi = match caller_abi {
Abi::Rust | Abi::RustCall => true,
_ => false
};
+ // We have two iterators: Where the arguments come from,
+ // and where they go to.
// For where they come from: If the ABI is RustCall, we untuple the
// last incoming argument. These two iterators do not have the same type,
}
// Now we should have no more caller args
if caller_iter.next().is_some() {
- trace!("Caller has too many args over");
+ trace!("Caller has passed too many args");
return err!(FunctionArgCountMismatch);
}
// Don't forget to check the return type!
}
// cannot use the shim here, because that will only result in infinite recursion
ty::InstanceDef::Virtual(_, idx) => {
+ let mut args = args.to_vec();
let ptr_size = self.pointer_size();
- let ptr = self.deref_operand(args[0])?;
- let vtable = ptr.vtable()?;
+ // We have to implement all "object safe receivers". Currently we
+ // support built-in pointers (&, &mut, Box) as well as unsized-self. We do
+ // not yet support custom self types.
+ // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs.
+ let receiver_place = match args[0].layout.ty.builtin_deref(true) {
+ Some(_) => {
+ // Built-in pointer.
+ self.deref_operand(args[0])?
+ }
+ None => {
+ // Unsized self.
+ args[0].to_mem_place()
+ }
+ };
+ // Find and consult vtable
+ let vtable = receiver_place.vtable()?;
self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?;
let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized(
self,
)?.to_ptr()?;
let instance = self.memory.get_fn(fn_ptr)?;
- // We have to patch the self argument, in particular get the layout
- // expected by the actual function. Cannot just use "field 0" due to
- // Box<self>.
- let mut args = args.to_vec();
- let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
- let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
- args[0] = OpTy::from(ImmTy { // strip vtable
- layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?,
- imm: Immediate::Scalar(ptr.ptr.into())
+ // `*mut receiver_place.layout.ty` is almost the layout that we
+ // want for args[0]: We have to project to field 0 because we want
+ // a thin pointer.
+ assert!(receiver_place.layout.is_unsized());
+ let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty);
+ let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?;
+ // Adjust receiver argument.
+ args[0] = OpTy::from(ImmTy {
+ layout: this_receiver_ptr,
+ imm: Immediate::Scalar(receiver_place.ptr.into())
});
trace!("Patched self operand to {:#?}", args[0]);
// recurse with concrete function