fix comparing of function pointers
This commit is contained in:
parent
d9776427b4
commit
e90ee1674a
4 changed files with 37 additions and 9 deletions
|
@ -1404,6 +1404,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
(8, &ty::TyUint(UintTy::Us)) |
|
||||
(_, &ty::TyUint(UintTy::U64)) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
|
||||
|
||||
(_, &ty::TyFnDef(def_id, substs, fn_ty)) => {
|
||||
PrimVal::FnPtr(self.memory.create_fn_ptr(def_id, substs, fn_ty))
|
||||
},
|
||||
(_, &ty::TyFnPtr(_)) => self.memory.read_ptr(ptr).map(PrimVal::FnPtr)?,
|
||||
(_, &ty::TyRef(_, ty::TypeAndMut { ty, .. })) |
|
||||
(_, &ty::TyRawPtr(ty::TypeAndMut { ty, .. })) => {
|
||||
if self.type_is_sized(ty) {
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Pointer {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct FunctionDefinition<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
|
@ -59,6 +59,8 @@ pub struct Memory<'tcx> {
|
|||
/// Function "allocations". They exist solely so pointers have something to point to, and
|
||||
/// we can figure out what they point to.
|
||||
functions: HashMap<AllocId, FunctionDefinition<'tcx>>,
|
||||
/// Inverse map of `functions` so we don't allocate a new pointer every time we need one
|
||||
function_definitions: HashMap<FunctionDefinition<'tcx>, AllocId>,
|
||||
next_id: AllocId,
|
||||
pub pointer_size: usize,
|
||||
}
|
||||
|
@ -69,22 +71,29 @@ impl<'tcx> Memory<'tcx> {
|
|||
Memory {
|
||||
alloc_map: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
function_definitions: HashMap::new(),
|
||||
next_id: AllocId(0),
|
||||
pointer_size: pointer_size,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: never create two pointers to the same def_id + substs combination
|
||||
// maybe re-use the statics cache of the EvalContext?
|
||||
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
|
||||
let id = self.next_id;
|
||||
debug!("creating fn ptr: {}", id);
|
||||
self.next_id.0 += 1;
|
||||
self.functions.insert(id, FunctionDefinition {
|
||||
let def = FunctionDefinition {
|
||||
def_id: def_id,
|
||||
substs: substs,
|
||||
fn_ty: fn_ty,
|
||||
});
|
||||
};
|
||||
if let Some(&alloc_id) = self.function_definitions.get(&def) {
|
||||
return Pointer {
|
||||
alloc_id: alloc_id,
|
||||
offset: 0,
|
||||
};
|
||||
}
|
||||
let id = self.next_id;
|
||||
debug!("creating fn ptr: {}", id);
|
||||
self.next_id.0 += 1;
|
||||
self.functions.insert(id, def);
|
||||
self.function_definitions.insert(def, id);
|
||||
Pointer {
|
||||
alloc_id: id,
|
||||
offset: 0,
|
||||
|
@ -361,6 +370,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
PrimVal::U32(n) => self.write_uint(ptr, n as u64, 4),
|
||||
PrimVal::U64(n) => self.write_uint(ptr, n as u64, 8),
|
||||
PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
|
||||
PrimVal::FnPtr(_p) |
|
||||
PrimVal::AbstractPtr(_p) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ pub enum PrimVal {
|
|||
U8(u8), U16(u16), U32(u32), U64(u64),
|
||||
|
||||
AbstractPtr(Pointer),
|
||||
FnPtr(Pointer),
|
||||
IntegerPtr(u64),
|
||||
}
|
||||
|
||||
|
@ -130,9 +131,20 @@ pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> Eva
|
|||
|
||||
(IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),
|
||||
|
||||
(AbstractPtr(_), IntegerPtr(_)) | (IntegerPtr(_), AbstractPtr(_)) =>
|
||||
(AbstractPtr(_), IntegerPtr(_)) |
|
||||
(IntegerPtr(_), AbstractPtr(_)) |
|
||||
(FnPtr(_), AbstractPtr(_)) |
|
||||
(AbstractPtr(_), FnPtr(_)) |
|
||||
(FnPtr(_), IntegerPtr(_)) |
|
||||
(IntegerPtr(_), FnPtr(_)) =>
|
||||
return unrelated_ptr_ops(bin_op),
|
||||
|
||||
(FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
|
||||
Eq => Bool(l_ptr == r_ptr),
|
||||
Ne => Bool(l_ptr != r_ptr),
|
||||
_ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
|
||||
},
|
||||
|
||||
(AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
|
||||
if l_ptr.alloc_id != r_ptr.alloc_id {
|
||||
return unrelated_ptr_ops(bin_op);
|
||||
|
|
|
@ -12,4 +12,6 @@ fn call_fn_ptr() -> i32 {
|
|||
|
||||
fn main() {
|
||||
assert_eq!(call_fn_ptr(), 42);
|
||||
assert!(return_fn_ptr() == f);
|
||||
assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue