diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 6454c764127..bb5f944fa36 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1552,6 +1552,38 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } } + + /// convenience function to ensure correct usage of globals and code-sharing with locals + pub fn modify_global< + F: FnOnce(&mut Self, Option) -> EvalResult<'tcx, Value>, + >( + &mut self, + cid: GlobalId<'tcx>, + f: F, + ) -> EvalResult<'tcx, ()> { + let mut val = *self.globals.get(&cid).expect("global not cached"); + if !val.mutable { + return Err(EvalError::ModifiedConstantMemory); + } + val.data = Some(f(self, val.data)?); + *self.globals.get_mut(&cid).expect("already checked") = val; + Ok(()) + } + + /// convenience function to ensure correct usage of locals and code-sharing with globals + pub fn modify_local< + F: FnOnce(&mut Self, Option) -> EvalResult<'tcx, Value>, + >( + &mut self, + frame: usize, + local: mir::Local, + f: F, + ) -> EvalResult<'tcx, ()> { + let val = self.stack[frame].get_local(local); + let val = f(self, val)?; + self.stack[frame].set_local(local, val); + Ok(()) + } } impl<'tcx> Frame<'tcx> { diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index 2b10f825038..dfa4a427e90 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -127,52 +127,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "init" => { let size = dest_layout.size(&self.tcx.data_layout).bytes() as usize; - match dest { - Lvalue::Local { frame, local } => { - match self.stack[frame].get_local(local) { - Some(Value::ByRef(ptr)) => self.memory.write_repeat(ptr, 0, size)?, - None => match self.ty_to_primval_kind(dest_ty) { - Ok(kind) => self.stack[frame].set_local(local, Value::ByVal(PrimVal::new(0, kind))), - Err(_) => { - let ptr = self.alloc_ptr_with_substs(dest_ty, substs)?; - self.memory.write_repeat(ptr, 0, size)?; - self.stack[frame].set_local(local, Value::ByRef(ptr)); - } - }, - Some(Value::ByVal(val)) => self.stack[frame].set_local(local, Value::ByVal(PrimVal::new(0, val.kind))), - Some(Value::ByValPair(a, b)) => self.stack[frame].set_local(local, Value::ByValPair( - PrimVal::new(0, a.kind), - PrimVal::new(0, b.kind), - )), - } + let init = |this: &mut Self, val: Option| { + match val { + Some(Value::ByRef(ptr)) => { + this.memory.write_repeat(ptr, 0, size)?; + Ok(Value::ByRef(ptr)) + }, + None => match this.ty_to_primval_kind(dest_ty) { + Ok(kind) => Ok(Value::ByVal(PrimVal::new(0, kind))), + Err(_) => { + let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; + this.memory.write_repeat(ptr, 0, size)?; + Ok(Value::ByRef(ptr)) + } + }, + Some(Value::ByVal(value)) => Ok(Value::ByVal(PrimVal::new(0, value.kind))), + Some(Value::ByValPair(a, b)) => Ok(Value::ByValPair( + PrimVal::new(0, a.kind), + PrimVal::new(0, b.kind), + )), } + }; + match dest { + Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, Lvalue::Ptr { ptr, extra: LvalueExtra::None } => self.memory.write_repeat(ptr, 0, size)?, Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat ptr target"), - Lvalue::Global(cid) => { - let global_val = *self.globals.get(&cid).expect("global not cached"); - if !global_val.mutable { - return Err(EvalError::ModifiedConstantMemory); - } - match global_val.data { - Some(Value::ByRef(ptr)) => self.memory.write_repeat(ptr, 0, size)?, - None => match self.ty_to_primval_kind(dest_ty) { - Ok(kind) => self.globals - .get_mut(&cid) - .expect("already checked") - .data = Some(Value::ByVal(PrimVal::new(0, kind))), - Err(_) => { - let ptr = self.alloc_ptr_with_substs(dest_ty, substs)?; - self.memory.write_repeat(ptr, 0, size)?; - self.globals.get_mut(&cid).expect("already checked").data = Some(Value::ByRef(ptr)); - }, - }, - Some(Value::ByVal(val)) => self.globals.get_mut(&cid).expect("already checked").data = Some(Value::ByVal(PrimVal::new(0, val.kind))), - Some(Value::ByValPair(a, b)) => self.globals.get_mut(&cid).expect("already checked").data = Some(Value::ByValPair( - PrimVal::new(0, a.kind), - PrimVal::new(0, b.kind), - )), - } - } + Lvalue::Global(cid) => self.modify_global(cid, init)?, } }