diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 36d9c0b481f1a..79ef3f97a9e9a 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -176,8 +176,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Lvalue::undef(), StackPopCleanup::Goto(dest_block), )?; + let mut args = self.frame().mir.args_iter(); - let arg_local = self.frame().mir.args_iter().next().ok_or( + let arg_local = args.next().ok_or( EvalErrorKind::AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), @@ -186,6 +187,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; self.write_ptr(arg_dest, data, u8_ptr_ty)?; + assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); + // We ourselves return 0 self.write_null(dest, dest_ty)?; diff --git a/miri/lib.rs b/miri/lib.rs index 428724f7de5d9..f6ecd6e0b00b7 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -114,6 +114,8 @@ pub fn eval_main<'a, 'tcx: 'a>( ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); } else { ecx.push_stack_frame( main_instance, @@ -122,6 +124,10 @@ pub fn eval_main<'a, 'tcx: 'a>( Lvalue::undef(), StackPopCleanup::None, )?; + + // No arguments + let mut args = ecx.frame().mir.args_iter(); + assert!(args.next().is_none(), "main function must not have arguments"); } while ecx.step()? {} @@ -227,17 +233,52 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - // FIXME: call the `exchange_malloc` lang item if available + dest: Lvalue, + ) -> EvalResult<'tcx> { let size = ecx.type_size(ty)?.expect("box only works with sized types"); let align = ecx.type_align(ty)?; - if size == 0 { - Ok(PrimVal::Bytes(align.into())) - } else { - ecx.memory - .allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust)) - .map(PrimVal::Ptr) - } + + // Call the `exchange_malloc` lang item + let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); + let malloc = ty::Instance::mono(ecx.tcx, malloc); + let malloc_mir = ecx.load_mir(malloc.def)?; + ecx.push_stack_frame( + malloc, + malloc_mir.span, + malloc_mir, + dest, + // Don't do anything when we are done. The statement() function will increment + // the old stack frame's stmt counter to the next statement, which means that when + // exchange_malloc returns, we go on evaluating exactly where we want to be. + StackPopCleanup::None, + )?; + + let mut args = ecx.frame().mir.args_iter(); + let usize = ecx.tcx.types.usize; + + // First argument: size + let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + ecx.write_value( + ValTy { + value: Value::ByVal(PrimVal::Bytes(size as u128)), + ty: usize, + }, + dest, + )?; + + // Second argument: align + let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + ecx.write_value( + ValTy { + value: Value::ByVal(PrimVal::Bytes(align as u128)), + ty: usize, + }, + dest, + )?; + + // No more arguments + assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected"); + Ok(()) } fn global_item_with_linkage<'a>( diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 7fa28dccbabe4..075880fc5bfd1 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -240,7 +240,8 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator { fn box_alloc<'a>( _ecx: &mut EvalContext<'a, 'tcx, Self>, _ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { + _dest: Lvalue, + ) -> EvalResult<'tcx> { Err( ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(), ) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 0d761c245936c..3388031a30cab 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -877,8 +877,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } NullaryOp(mir::NullOp::Box, ty) => { - let ptr = M::box_alloc(self, ty)?; - self.write_primval(dest, ptr, dest_ty)?; + M::box_alloc(self, ty, dest)?; } NullaryOp(mir::NullOp::SizeOf, ty) => { diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index 7fb6ac4209f17..36b396a7a2ba5 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(Lvalue::Ptr { ptr, extra }) } - pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { + pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { self.monomorphize( lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx), self.substs(), diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index debb17fc0a7f9..3df5d1b6a31be 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -70,7 +70,8 @@ pub trait Machine<'tcx>: Sized { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, PrimVal>; + dest: Lvalue, + ) -> EvalResult<'tcx>; /// Called when trying to access a global declared with a `linkage` attribute fn global_item_with_linkage<'a>( diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 1f538707527f2..c701ebfbf4c75 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -92,6 +92,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { trace!("{:?}", stmt); use rustc::mir::StatementKind::*; + + // Some statements (e.g. box) push new stack frames. We have to record the stack frame number + // *before* executing the statement. + let frame_idx = self.cur_frame(); + match stmt.kind { Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?, @@ -175,7 +180,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { InlineAsm { .. } => return err!(InlineAsm), } - self.frame_mut().stmt += 1; + self.stack[frame_idx].stmt += 1; Ok(()) }