fix comparing of function pointers

上级 d9776427
......@@ -1404,6 +1404,10 @@ pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, P
(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 @@ pub fn offset(self, i: isize) -> Self {
}
}
#[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 @@ pub fn new(pointer_size: usize) -> Self {
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 @@ pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<'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 @@ fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
(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);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册