Merge pull request #48 from oli-obk/fix_call_stack_positions
change the block and stmt position after a function call returns
This commit is contained in:
commit
f1dc961c5a
@ -71,6 +71,9 @@ pub struct Frame<'a, 'tcx: 'a> {
|
||||
/// A pointer for writing the return value of the current call if it's not a diverging call.
|
||||
pub return_ptr: Option<Pointer>,
|
||||
|
||||
/// The block to return to when returning from the current stack frame
|
||||
pub return_to_block: Option<mir::BasicBlock>,
|
||||
|
||||
/// The list of locals for the current function, stored in order as
|
||||
/// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
|
||||
/// and the temporaries at `self.temp_offset`.
|
||||
@ -305,6 +308,7 @@ pub fn push_stack_frame(
|
||||
mir: CachedMir<'a, 'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
return_ptr: Option<Pointer>,
|
||||
return_to_block: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
|
||||
let var_tys = mir.var_decls.iter().map(|v| v.ty);
|
||||
@ -325,6 +329,7 @@ pub fn push_stack_frame(
|
||||
mir: mir.clone(),
|
||||
block: mir::START_BLOCK,
|
||||
return_ptr: return_ptr,
|
||||
return_to_block: return_to_block,
|
||||
locals: locals?,
|
||||
var_offset: num_args,
|
||||
temp_offset: num_args + num_vars,
|
||||
@ -342,7 +347,10 @@ pub fn push_stack_frame(
|
||||
|
||||
fn pop_stack_frame(&mut self) {
|
||||
::log_settings::settings().indentation -= 1;
|
||||
let _frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
|
||||
let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
|
||||
if let Some(target) = frame.return_to_block {
|
||||
self.goto_block(target);
|
||||
}
|
||||
// TODO(solson): Deallocate local variables.
|
||||
}
|
||||
|
||||
@ -961,7 +969,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
|
||||
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs)
|
||||
.expect("should at least be able to allocate space for the main function's return value");
|
||||
|
||||
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr))
|
||||
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr), None)
|
||||
.expect("could not allocate first stack frame");
|
||||
|
||||
if mir.arg_decls.len() == 2 {
|
||||
|
@ -87,8 +87,6 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
}
|
||||
|
||||
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
// after a terminator we go to a new block
|
||||
self.frame_mut().stmt = 0;
|
||||
trace!("{:?}", terminator.kind);
|
||||
self.eval_terminator(terminator)?;
|
||||
if !self.stack.is_empty() {
|
||||
@ -125,7 +123,7 @@ fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span
|
||||
self.try(|this| {
|
||||
let ptr = this.ecx.alloc_ret_ptr(mir.return_ty, substs)?;
|
||||
this.ecx.statics.insert(cid.clone(), ptr);
|
||||
this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr))
|
||||
this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), None)
|
||||
});
|
||||
}
|
||||
fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
|
||||
@ -170,7 +168,7 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Loca
|
||||
let return_ptr = this.ecx.alloc_ret_ptr(return_ty, cid.substs)?;
|
||||
let mir = CachedMir::Owned(Rc::new(mir));
|
||||
this.ecx.statics.insert(cid.clone(), return_ptr);
|
||||
this.ecx.push_stack_frame(this.def_id, constant.span, mir, this.substs, Some(return_ptr))
|
||||
this.ecx.push_stack_frame(this.def_id, constant.span, mir, this.substs, Some(return_ptr), None)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,12 @@
|
||||
use memory::{Pointer, FunctionDefinition};
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
pub(super) fn goto_block(&mut self, target: mir::BasicBlock) {
|
||||
self.frame_mut().block = target;
|
||||
self.frame_mut().stmt = 0;
|
||||
}
|
||||
|
||||
pub(super) fn eval_terminator(
|
||||
&mut self,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
@ -23,14 +29,12 @@ pub(super) fn eval_terminator(
|
||||
match terminator.kind {
|
||||
Return => self.pop_stack_frame(),
|
||||
|
||||
Goto { target } => {
|
||||
self.frame_mut().block = target;
|
||||
},
|
||||
Goto { target } => self.goto_block(target),
|
||||
|
||||
If { ref cond, targets: (then_target, else_target) } => {
|
||||
let cond_ptr = self.eval_operand(cond)?;
|
||||
let cond_val = self.memory.read_bool(cond_ptr)?;
|
||||
self.frame_mut().block = if cond_val { then_target } else { else_target };
|
||||
self.goto_block(if cond_val { then_target } else { else_target });
|
||||
}
|
||||
|
||||
SwitchInt { ref discr, ref values, ref targets, .. } => {
|
||||
@ -59,7 +63,7 @@ pub(super) fn eval_terminator(
|
||||
}
|
||||
}
|
||||
|
||||
self.frame_mut().block = target_block;
|
||||
self.goto_block(target_block);
|
||||
}
|
||||
|
||||
Switch { ref discr, ref targets, adt_def } => {
|
||||
@ -70,19 +74,16 @@ pub(super) fn eval_terminator(
|
||||
.position(|v| discr_val == v.disr_val.to_u64_unchecked());
|
||||
|
||||
match matching {
|
||||
Some(i) => {
|
||||
self.frame_mut().block = targets[i];
|
||||
},
|
||||
Some(i) => self.goto_block(targets[i]),
|
||||
None => return Err(EvalError::InvalidDiscriminant),
|
||||
}
|
||||
}
|
||||
|
||||
Call { ref func, ref args, ref destination, .. } => {
|
||||
let mut return_ptr = None;
|
||||
if let Some((ref lv, target)) = *destination {
|
||||
self.frame_mut().block = target;
|
||||
return_ptr = Some(self.eval_lvalue(lv)?.to_ptr());
|
||||
}
|
||||
let destination = match *destination {
|
||||
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?.to_ptr(), target)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let func_ty = self.operand_ty(func);
|
||||
match func_ty.sty {
|
||||
@ -93,11 +94,11 @@ pub(super) fn eval_terminator(
|
||||
if fn_ty != bare_fn_ty {
|
||||
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
|
||||
}
|
||||
self.eval_fn_call(def_id, substs, bare_fn_ty, return_ptr, args,
|
||||
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
|
||||
terminator.source_info.span)?
|
||||
},
|
||||
ty::TyFnDef(def_id, substs, fn_ty) => {
|
||||
self.eval_fn_call(def_id, substs, fn_ty, return_ptr, args,
|
||||
self.eval_fn_call(def_id, substs, fn_ty, destination, args,
|
||||
terminator.source_info.span)?
|
||||
}
|
||||
|
||||
@ -109,13 +110,13 @@ pub(super) fn eval_terminator(
|
||||
let ptr = self.eval_lvalue(location)?.to_ptr();
|
||||
let ty = self.lvalue_ty(location);
|
||||
self.drop(ptr, ty)?;
|
||||
self.frame_mut().block = target;
|
||||
self.goto_block(target);
|
||||
}
|
||||
|
||||
Assert { ref cond, expected, ref msg, target, .. } => {
|
||||
let cond_ptr = self.eval_operand(cond)?;
|
||||
if expected == self.memory.read_bool(cond_ptr)? {
|
||||
self.frame_mut().block = target;
|
||||
self.goto_block(target);
|
||||
} else {
|
||||
return match *msg {
|
||||
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
@ -143,7 +144,7 @@ fn eval_fn_call(
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
fn_ty: &'tcx BareFnTy,
|
||||
return_ptr: Option<Pointer>,
|
||||
destination: Option<(Pointer, mir::BasicBlock)>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
span: Span,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
@ -152,14 +153,19 @@ fn eval_fn_call(
|
||||
Abi::RustIntrinsic => {
|
||||
let ty = fn_ty.sig.0.output;
|
||||
let layout = self.type_layout(ty);
|
||||
let ret = return_ptr.unwrap();
|
||||
self.call_intrinsic(def_id, substs, args, ret, layout)
|
||||
let (ret, target) = destination.unwrap();
|
||||
self.call_intrinsic(def_id, substs, args, ret, layout)?;
|
||||
self.goto_block(target);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Abi::C => {
|
||||
let ty = fn_ty.sig.0.output;
|
||||
let size = self.type_size(ty);
|
||||
self.call_c_abi(def_id, args, return_ptr.unwrap(), size)
|
||||
let (ret, target) = destination.unwrap();
|
||||
self.call_c_abi(def_id, args, ret, size)?;
|
||||
self.goto_block(target);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Abi::Rust | Abi::RustCall => {
|
||||
@ -203,7 +209,11 @@ fn eval_fn_call(
|
||||
}
|
||||
|
||||
let mir = self.load_mir(resolved_def_id);
|
||||
self.push_stack_frame(def_id, span, mir, resolved_substs, return_ptr)?;
|
||||
let (return_ptr, return_to_block) = match destination {
|
||||
Some((ptr, block)) => (Some(ptr), Some(block)),
|
||||
None => (None, None),
|
||||
};
|
||||
self.push_stack_frame(def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
|
||||
|
||||
for (i, (src, src_ty)) in arg_srcs.into_iter().enumerate() {
|
||||
let dest = self.frame().locals[i];
|
||||
|
@ -1,9 +1,9 @@
|
||||
fn main() {
|
||||
fn f() {}
|
||||
|
||||
let g = unsafe { //~ ERROR tried to call a function of type
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn(), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42)
|
||||
g(42) //~ ERROR tried to call a function of type
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ fn main() {
|
||||
let x = box 42;
|
||||
unsafe {
|
||||
let f = std::mem::transmute::<Box<i32>, fn()>(x);
|
||||
//~^ ERROR: tried to treat a memory pointer as a function pointer
|
||||
f()
|
||||
f() //~ ERROR: tried to treat a memory pointer as a function pointer
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,6 @@ fn bar() {
|
||||
assert_eq!(x, 6);
|
||||
}
|
||||
|
||||
fn main() { //~ ERROR tried to allocate 4 more bytes, but only 0 bytes are free of the 0 byte memory
|
||||
bar();
|
||||
fn main() {
|
||||
bar(); //~ ERROR tried to allocate 4 more bytes, but only 0 bytes are free of the 0 byte memory
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user