Merge branch 'master' of https://github.com/tsion/miri
This commit is contained in:
commit
17e336c7d9
6 changed files with 89 additions and 63 deletions
|
@ -28,7 +28,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
U64(u) |
|
U64(u) |
|
||||||
IntegerPtr(u) => self.cast_const_int(u, ty, false),
|
IntegerPtr(u) => self.cast_const_int(u, ty, false),
|
||||||
FnPtr(ptr) |
|
FnPtr(ptr) |
|
||||||
AbstractPtr(ptr) => self.cast_ptr(ptr, ty),
|
Ptr(ptr) => self.cast_ptr(ptr, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
use primval::PrimVal::*;
|
use primval::PrimVal::*;
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::TyRef(..) |
|
ty::TyRef(..) |
|
||||||
ty::TyRawPtr(_) => Ok(AbstractPtr(ptr)),
|
ty::TyRawPtr(_) => Ok(Ptr(ptr)),
|
||||||
ty::TyFnPtr(_) => Ok(FnPtr(ptr)),
|
ty::TyFnPtr(_) => Ok(FnPtr(ptr)),
|
||||||
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
|
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
self.memory.write_bytes(ptr, s.as_bytes())?;
|
self.memory.write_bytes(ptr, s.as_bytes())?;
|
||||||
self.memory.freeze(ptr.alloc_id)?;
|
self.memory.freeze(ptr.alloc_id)?;
|
||||||
Value::ByValPair(
|
Value::ByValPair(
|
||||||
PrimVal::AbstractPtr(ptr),
|
PrimVal::Ptr(ptr),
|
||||||
self.target_usize_primval(s.len() as u64)
|
self.target_usize_primval(s.len() as u64)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
let ptr = self.memory.allocate(bs.len(), 1)?;
|
let ptr = self.memory.allocate(bs.len(), 1)?;
|
||||||
self.memory.write_bytes(ptr, bs)?;
|
self.memory.write_bytes(ptr, bs)?;
|
||||||
self.memory.freeze(ptr.alloc_id)?;
|
self.memory.freeze(ptr.alloc_id)?;
|
||||||
Value::ByVal(PrimVal::AbstractPtr(ptr))
|
Value::ByVal(PrimVal::Ptr(ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(_) => unimplemented!(),
|
Struct(_) => unimplemented!(),
|
||||||
|
@ -782,31 +782,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
// remove it as soon as PrimVal can represent fat pointers.
|
// remove it as soon as PrimVal can represent fat pointers.
|
||||||
fn eval_operand_to_ptr(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Pointer> {
|
fn eval_operand_to_ptr(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||||
let value = self.eval_operand(op)?;
|
let value = self.eval_operand(op)?;
|
||||||
match value {
|
let ty = self.operand_ty(op);
|
||||||
Value::ByRef(ptr) => Ok(ptr),
|
self.value_to_ptr(value, ty)
|
||||||
|
|
||||||
Value::ByVal(primval) => {
|
|
||||||
let ty = self.operand_ty(op);
|
|
||||||
let size = self.type_size(ty);
|
|
||||||
let align = self.type_align(ty);
|
|
||||||
let ptr = self.memory.allocate(size, align)?;
|
|
||||||
self.memory.write_primval(ptr, primval)?;
|
|
||||||
Ok(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::ByValPair(primval1, primval2) => {
|
|
||||||
let ty = self.operand_ty(op);
|
|
||||||
let size = self.type_size(ty);
|
|
||||||
let align = self.type_align(ty);
|
|
||||||
let ptr = self.memory.allocate(size, align)?;
|
|
||||||
|
|
||||||
// FIXME(solson): Major dangerous assumptions here. Ideally obliterate this
|
|
||||||
// function.
|
|
||||||
self.memory.write_primval(ptr, primval1)?;
|
|
||||||
self.memory.write_primval(ptr.offset((size / 2) as isize), primval2)?;
|
|
||||||
Ok(ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
||||||
|
@ -992,6 +969,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(solson): This method unnecessarily allocates and should not be necessary. We can
|
||||||
|
// remove it as soon as PrimVal can represent fat pointers.
|
||||||
|
fn value_to_ptr(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||||
|
match value {
|
||||||
|
Value::ByRef(ptr) => Ok(ptr),
|
||||||
|
|
||||||
|
Value::ByVal(primval) => {
|
||||||
|
let size = self.type_size(ty);
|
||||||
|
let align = self.type_align(ty);
|
||||||
|
let ptr = self.memory.allocate(size, align)?;
|
||||||
|
self.memory.write_primval(ptr, primval)?;
|
||||||
|
Ok(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::ByValPair(primval1, primval2) => {
|
||||||
|
let size = self.type_size(ty);
|
||||||
|
let align = self.type_align(ty);
|
||||||
|
let ptr = self.memory.allocate(size, align)?;
|
||||||
|
|
||||||
|
// FIXME(solson): Major dangerous assumptions here. Ideally obliterate this
|
||||||
|
// function.
|
||||||
|
self.memory.write_primval(ptr, primval1)?;
|
||||||
|
self.memory.write_primval(ptr.offset((size / 2) as isize), primval2)?;
|
||||||
|
Ok(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
|
||||||
match value {
|
match value {
|
||||||
Value::ByRef(ptr) => self.read_primval(ptr, ty),
|
Value::ByRef(ptr) => self.read_primval(ptr, ty),
|
||||||
|
@ -1057,7 +1062,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
&ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
|
&ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
|
||||||
if self.type_is_sized(ty) {
|
if self.type_is_sized(ty) {
|
||||||
match self.memory.read_ptr(ptr) {
|
match self.memory.read_ptr(ptr) {
|
||||||
Ok(p) => PrimVal::AbstractPtr(p),
|
Ok(p) => PrimVal::Ptr(p),
|
||||||
Err(EvalError::ReadBytesAsPointer) => {
|
Err(EvalError::ReadBytesAsPointer) => {
|
||||||
PrimVal::IntegerPtr(self.memory.read_usize(ptr)?)
|
PrimVal::IntegerPtr(self.memory.read_usize(ptr)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
|
|
||||||
// Miri can safely ignore these. Only translation needs them.
|
// Miri can safely ignore these. Only translation needs them.
|
||||||
StorageLive(_) | StorageDead(_) => {}
|
StorageLive(_) | StorageDead(_) => {}
|
||||||
|
|
||||||
|
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||||
|
// size of MIR constantly.
|
||||||
|
Nop => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.frame_mut().stmt += 1;
|
self.frame_mut().stmt += 1;
|
||||||
|
@ -186,12 +190,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext, location: mir::Location) {
|
fn visit_lvalue(
|
||||||
|
&mut self,
|
||||||
|
lvalue: &mir::Lvalue<'tcx>,
|
||||||
|
context: LvalueContext<'tcx>,
|
||||||
|
location: mir::Location
|
||||||
|
) {
|
||||||
self.super_lvalue(lvalue, context, location);
|
self.super_lvalue(lvalue, context, location);
|
||||||
if let mir::Lvalue::Static(def_id) = *lvalue {
|
if let mir::Lvalue::Static(def_id) = *lvalue {
|
||||||
let substs = subst::Substs::empty(self.ecx.tcx);
|
let substs = subst::Substs::empty(self.ecx.tcx);
|
||||||
let span = self.span;
|
let span = self.span;
|
||||||
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = self.ecx.tcx.map.get_if_local(def_id).expect("static not found") {
|
let node_item = self.ecx.tcx.map.get_if_local(def_id).expect("static not found");
|
||||||
|
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
|
||||||
if let hir::ItemStatic(_, m, _) = *node {
|
if let hir::ItemStatic(_, m, _) = *node {
|
||||||
self.global_item(def_id, substs, span, m == hir::MutImmutable);
|
self.global_item(def_id, substs, span, m == hir::MutImmutable);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,7 +13,8 @@ use syntax::{ast, attr};
|
||||||
|
|
||||||
use error::{EvalError, EvalResult};
|
use error::{EvalError, EvalResult};
|
||||||
use memory::Pointer;
|
use memory::Pointer;
|
||||||
use super::{EvalContext, IntegerExt, StackPopCleanup};
|
use primval::PrimVal;
|
||||||
|
use super::{EvalContext, IntegerExt, StackPopCleanup, Value};
|
||||||
|
|
||||||
mod intrinsics;
|
mod intrinsics;
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
substs: &'tcx Substs<'tcx>,
|
substs: &'tcx Substs<'tcx>,
|
||||||
fn_ty: &'tcx BareFnTy,
|
fn_ty: &'tcx BareFnTy,
|
||||||
destination: Option<(Pointer, mir::BasicBlock)>,
|
destination: Option<(Pointer, mir::BasicBlock)>,
|
||||||
args: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> EvalResult<'tcx, ()> {
|
) -> EvalResult<'tcx, ()> {
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
|
@ -163,7 +164,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
let ty = fn_ty.sig.0.output;
|
let ty = fn_ty.sig.0.output;
|
||||||
let layout = self.type_layout(ty);
|
let layout = self.type_layout(ty);
|
||||||
let (ret, target) = destination.unwrap();
|
let (ret, target) = destination.unwrap();
|
||||||
self.call_intrinsic(def_id, substs, args, ret, layout)?;
|
self.call_intrinsic(def_id, substs, arg_operands, ret, layout)?;
|
||||||
self.goto_block(target);
|
self.goto_block(target);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -172,23 +173,23 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
let ty = fn_ty.sig.0.output;
|
let ty = fn_ty.sig.0.output;
|
||||||
let size = self.type_size(ty);
|
let size = self.type_size(ty);
|
||||||
let (ret, target) = destination.unwrap();
|
let (ret, target) = destination.unwrap();
|
||||||
self.call_c_abi(def_id, args, ret, size)?;
|
self.call_c_abi(def_id, arg_operands, ret, size)?;
|
||||||
self.goto_block(target);
|
self.goto_block(target);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Abi::Rust | Abi::RustCall => {
|
Abi::Rust | Abi::RustCall => {
|
||||||
let mut arg_srcs = Vec::new();
|
let mut args = Vec::new();
|
||||||
for arg in args {
|
for arg in arg_operands {
|
||||||
let src = self.eval_operand_to_ptr(arg)?;
|
let arg_val = self.eval_operand(arg)?;
|
||||||
let src_ty = self.operand_ty(arg);
|
let arg_ty = self.operand_ty(arg);
|
||||||
arg_srcs.push((src, src_ty));
|
args.push((arg_val, arg_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only trait methods can have a Self parameter.
|
// Only trait methods can have a Self parameter.
|
||||||
let (resolved_def_id, resolved_substs) =
|
let (resolved_def_id, resolved_substs) =
|
||||||
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
|
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
|
||||||
self.trait_method(trait_id, def_id, substs, &mut arg_srcs)?
|
self.trait_method(trait_id, def_id, substs, &mut args)?
|
||||||
} else {
|
} else {
|
||||||
(def_id, substs)
|
(def_id, substs)
|
||||||
};
|
};
|
||||||
|
@ -200,9 +201,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
|
self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
|
||||||
|
|
||||||
for (i, (src, src_ty)) in arg_srcs.into_iter().enumerate() {
|
for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
|
||||||
let dest = self.frame().locals[i];
|
let dest = self.frame().locals[i];
|
||||||
self.move_(src, dest, src_ty)?;
|
self.write_value(arg_val, dest, arg_ty)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -344,7 +345,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unpack_fn_args(&self, args: &mut Vec<(Pointer, Ty<'tcx>)>) {
|
fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) {
|
||||||
if let Some((last, last_ty)) = args.pop() {
|
if let Some((last, last_ty)) = args.pop() {
|
||||||
let last_layout = self.type_layout(last_ty);
|
let last_layout = self.type_layout(last_ty);
|
||||||
match (&last_ty.sty, last_layout) {
|
match (&last_ty.sty, last_layout) {
|
||||||
|
@ -353,9 +354,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
let offsets = iter::once(0)
|
let offsets = iter::once(0)
|
||||||
.chain(variant.offset_after_field.iter()
|
.chain(variant.offset_after_field.iter()
|
||||||
.map(|s| s.bytes()));
|
.map(|s| s.bytes()));
|
||||||
|
let last_ptr = match last {
|
||||||
|
Value::ByRef(ptr) => ptr,
|
||||||
|
_ => bug!("rust-call ABI tuple argument wasn't Value::ByRef"),
|
||||||
|
};
|
||||||
for (offset, ty) in offsets.zip(fields) {
|
for (offset, ty) in offsets.zip(fields) {
|
||||||
let src = last.offset(offset as isize);
|
let arg = Value::ByRef(last_ptr.offset(offset as isize));
|
||||||
args.push((src, ty));
|
args.push((arg, ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
|
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
|
||||||
|
@ -369,7 +374,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
trait_id: DefId,
|
trait_id: DefId,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: &'tcx Substs<'tcx>,
|
substs: &'tcx Substs<'tcx>,
|
||||||
args: &mut Vec<(Pointer, Ty<'tcx>)>,
|
args: &mut Vec<(Value, Ty<'tcx>)>,
|
||||||
) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>)> {
|
) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>)> {
|
||||||
let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs);
|
let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs);
|
||||||
let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
||||||
|
@ -398,6 +403,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
|
||||||
(ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) |
|
(ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) |
|
||||||
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {} // No adapter needed.
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {} // No adapter needed.
|
||||||
|
|
||||||
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
||||||
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
||||||
// The closure fn is a `fn(&self, ...)` or `fn(&mut self, ...)`.
|
// The closure fn is a `fn(&self, ...)` or `fn(&mut self, ...)`.
|
||||||
|
@ -409,13 +415,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
//
|
//
|
||||||
// These are both the same at trans time.
|
// These are both the same at trans time.
|
||||||
|
|
||||||
// interpreter magic: insert an intermediate pointer, so we can skip the intermediate function call
|
// Interpreter magic: insert an intermediate pointer, so we can skip the
|
||||||
// FIXME: this is a memory leak, should probably add the pointer to the current stack
|
// intermediate function call.
|
||||||
let ptr_size = self.memory.pointer_size();
|
// FIXME: this is a memory leak, should probably add the pointer to the
|
||||||
let first = self.memory.allocate(ptr_size, ptr_size)?;
|
// current stack.
|
||||||
self.memory.copy(args[0].0, first, ptr_size, ptr_size)?;
|
let first = self.value_to_ptr(args[0].0, args[0].1)?;
|
||||||
self.memory.write_ptr(args[0].0, first)?;
|
args[0].0 = Value::ByVal(PrimVal::Ptr(first));
|
||||||
|
args[0].1 = self.tcx.mk_mut_ptr(args[0].1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => bug!("cannot convert {:?} to {:?}", closure_kind, trait_closure_kind),
|
_ => bug!("cannot convert {:?} to {:?}", closure_kind, trait_closure_kind),
|
||||||
}
|
}
|
||||||
Ok((vtable_closure.closure_def_id, vtable_closure.substs.func_substs))
|
Ok((vtable_closure.closure_def_id, vtable_closure.substs.func_substs))
|
||||||
|
@ -433,8 +441,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
|
|
||||||
traits::VtableObject(ref data) => {
|
traits::VtableObject(ref data) => {
|
||||||
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id);
|
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id);
|
||||||
if let Some(&mut(first_arg, ref mut first_ty)) = args.get_mut(0) {
|
if let Some(&mut(ref mut first_arg, ref mut first_ty)) = args.get_mut(0) {
|
||||||
let (_, vtable) = self.get_fat_ptr(first_arg);
|
// FIXME(solson): Remove this allocating hack.
|
||||||
|
let ptr = self.value_to_ptr(*first_arg, *first_ty)?;
|
||||||
|
*first_arg = Value::ByRef(ptr);
|
||||||
|
let (_, vtable) = self.get_fat_ptr(ptr);
|
||||||
let vtable = self.memory.read_ptr(vtable)?;
|
let vtable = self.memory.read_ptr(vtable)?;
|
||||||
let idx = idx + 3;
|
let idx = idx + 3;
|
||||||
let offset = idx * self.memory.pointer_size();
|
let offset = idx * self.memory.pointer_size();
|
||||||
|
|
|
@ -530,7 +530,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||||
PrimVal::F32(f) => self.write_f32(ptr, f),
|
PrimVal::F32(f) => self.write_f32(ptr, f),
|
||||||
PrimVal::F64(f) => self.write_f64(ptr, f),
|
PrimVal::F64(f) => self.write_f64(ptr, f),
|
||||||
PrimVal::FnPtr(p) |
|
PrimVal::FnPtr(p) |
|
||||||
PrimVal::AbstractPtr(p) => self.write_ptr(ptr, p),
|
PrimVal::Ptr(p) => self.write_ptr(ptr, p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub enum PrimVal {
|
||||||
I8(i8), I16(i16), I32(i32), I64(i64),
|
I8(i8), I16(i16), I32(i32), I64(i64),
|
||||||
U8(u8), U16(u16), U32(u32), U64(u64),
|
U8(u8), U16(u16), U32(u32), U64(u64),
|
||||||
|
|
||||||
AbstractPtr(Pointer),
|
Ptr(Pointer),
|
||||||
FnPtr(Pointer),
|
FnPtr(Pointer),
|
||||||
IntegerPtr(u64),
|
IntegerPtr(u64),
|
||||||
Char(char),
|
Char(char),
|
||||||
|
@ -211,10 +211,10 @@ pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> Eva
|
||||||
|
|
||||||
(IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),
|
(IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),
|
||||||
|
|
||||||
(AbstractPtr(_), IntegerPtr(_)) |
|
(Ptr(_), IntegerPtr(_)) |
|
||||||
(IntegerPtr(_), AbstractPtr(_)) |
|
(IntegerPtr(_), Ptr(_)) |
|
||||||
(FnPtr(_), AbstractPtr(_)) |
|
(FnPtr(_), Ptr(_)) |
|
||||||
(AbstractPtr(_), FnPtr(_)) |
|
(Ptr(_), FnPtr(_)) |
|
||||||
(FnPtr(_), IntegerPtr(_)) |
|
(FnPtr(_), IntegerPtr(_)) |
|
||||||
(IntegerPtr(_), FnPtr(_)) =>
|
(IntegerPtr(_), FnPtr(_)) =>
|
||||||
unrelated_ptr_ops(bin_op)?,
|
unrelated_ptr_ops(bin_op)?,
|
||||||
|
@ -225,7 +225,7 @@ pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> Eva
|
||||||
_ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
|
_ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
|
||||||
},
|
},
|
||||||
|
|
||||||
(AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
|
(Ptr(l_ptr), Ptr(r_ptr)) => {
|
||||||
if l_ptr.alloc_id != r_ptr.alloc_id {
|
if l_ptr.alloc_id != r_ptr.alloc_id {
|
||||||
return Ok((unrelated_ptr_ops(bin_op)?, false));
|
return Ok((unrelated_ptr_ops(bin_op)?, false));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue