merge closures and function and implement some closure vtable cases
This commit is contained in:
parent
64155ffd10
commit
fd68670c0a
@ -1,14 +1,15 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{BareFnTy, Ty};
|
||||
use rustc::ty::{BareFnTy, Ty, FnSig};
|
||||
use syntax::abi::Abi;
|
||||
use memory::Pointer;
|
||||
use rustc_const_math::ConstMathErr;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum EvalError<'tcx> {
|
||||
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
|
||||
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
|
||||
NoMirFor(String),
|
||||
DanglingPointerDeref,
|
||||
InvalidMemoryAccess,
|
||||
@ -123,8 +124,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
||||
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
|
||||
},
|
||||
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
|
||||
EvalError::FunctionPointerTyMismatch(expected, got) =>
|
||||
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
|
||||
EvalError::FunctionPointerTyMismatch(abi, sig, got) =>
|
||||
write!(f, "tried to call a function with abi {:?} and sig {:?} through a function pointer of type {:?}", abi, sig, got),
|
||||
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
|
||||
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
|
||||
EvalError::Math(span, ref err) =>
|
||||
|
@ -666,7 +666,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
ReifyFnPointer => match self.operand_ty(operand).sty {
|
||||
ty::TyFnDef(def_id, substs, fn_ty) => {
|
||||
let fn_ty = self.tcx.erase_regions(&fn_ty);
|
||||
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
|
||||
let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
|
||||
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
|
||||
},
|
||||
ref other => bug!("reify fn pointer on {:?}", other),
|
||||
@ -676,9 +676,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
ty::TyFnPtr(unsafe_fn_ty) => {
|
||||
let src = self.eval_operand(operand)?;
|
||||
let ptr = src.read_ptr(&self.memory)?;
|
||||
let (def_id, substs, _) = self.memory.get_fn(ptr.alloc_id)?;
|
||||
let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
|
||||
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
|
||||
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, unsafe_fn_ty);
|
||||
let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty);
|
||||
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
|
||||
},
|
||||
ref other => bug!("fn to unsafe fn cast on {:?}", other),
|
||||
@ -1403,8 +1403,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
|
||||
|
||||
ty::TyFnDef(def_id, substs, fn_ty) => {
|
||||
let fn_ty = self.tcx.erase_regions(&fn_ty);
|
||||
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(def_id, substs, fn_ty))
|
||||
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
|
||||
},
|
||||
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_fn_ptr)?,
|
||||
ty::TyBox(ty) |
|
||||
|
@ -86,9 +86,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
match func_ty.sty {
|
||||
ty::TyFnPtr(bare_fn_ty) => {
|
||||
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
|
||||
let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
if fn_ty != bare_fn_ty {
|
||||
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
|
||||
let (def_id, substs, abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
if abi != bare_fn_ty.abi || sig != bare_fn_ty.sig.skip_binder() {
|
||||
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty));
|
||||
}
|
||||
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
|
||||
terminator.source_info.span)?
|
||||
@ -500,9 +500,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let idx = idx + 3;
|
||||
let offset = idx * self.memory.pointer_size();
|
||||
let fn_ptr = self.memory.read_ptr(vtable.offset(offset as isize))?;
|
||||
let (def_id, substs, ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
// FIXME: skip_binder is wrong for HKL
|
||||
*first_ty = ty.sig.skip_binder().inputs[0];
|
||||
let (def_id, substs, _abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
*first_ty = sig.inputs[0];
|
||||
Ok((def_id, substs))
|
||||
} else {
|
||||
Err(EvalError::VtableForArgumentlessMethod)
|
||||
@ -643,9 +642,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let drop_fn = self.memory.read_ptr(vtable)?;
|
||||
// some values don't need to call a drop impl, so the value is null
|
||||
if drop_fn != Pointer::from_int(0) {
|
||||
let (def_id, substs, ty) = self.memory.get_fn(drop_fn.alloc_id)?;
|
||||
let fn_sig = self.tcx.erase_late_bound_regions_and_normalize(&ty.sig);
|
||||
let real_ty = fn_sig.inputs[0];
|
||||
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?;
|
||||
let real_ty = sig.inputs[0];
|
||||
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
|
||||
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs));
|
||||
} else {
|
||||
|
@ -36,7 +36,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
.into_iter()
|
||||
.map(|opt_mth| opt_mth.map(|mth| {
|
||||
let fn_ty = self.tcx.erase_regions(&mth.method.fty);
|
||||
self.memory.create_fn_ptr(mth.method.def_id, mth.substs, fn_ty)
|
||||
self.memory.create_fn_ptr(self.tcx, mth.method.def_id, mth.substs, fn_ty)
|
||||
}))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
@ -47,14 +47,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
substs,
|
||||
nested: _ }) => {
|
||||
let closure_type = self.tcx.closure_type(closure_def_id, substs);
|
||||
let fn_ty = ty::BareFnTy {
|
||||
unsafety: closure_type.unsafety,
|
||||
abi: closure_type.abi,
|
||||
sig: closure_type.sig,
|
||||
};
|
||||
let _fn_ty = self.tcx.mk_bare_fn(fn_ty);
|
||||
unimplemented!()
|
||||
//vec![Some(self.memory.create_fn_ptr(closure_def_id, substs.func_substs, fn_ty))].into_iter()
|
||||
vec![Some(self.memory.create_closure_ptr(self.tcx, closure_def_id, substs, closure_type))].into_iter()
|
||||
}
|
||||
traits::VtableFnPointer(
|
||||
traits::VtableFnPointerData {
|
||||
@ -62,7 +55,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
nested: _ }) => {
|
||||
match fn_ty.sty {
|
||||
ty::TyFnDef(did, substs, bare_fn_ty) => {
|
||||
vec![Some(self.memory.create_fn_ptr(did, substs, bare_fn_ty))].into_iter()
|
||||
vec![Some(self.memory.create_fn_ptr(self.tcx, did, substs, bare_fn_ty))].into_iter()
|
||||
},
|
||||
_ => bug!("bad VtableFnPointer fn_ty: {:?}", fn_ty),
|
||||
}
|
||||
@ -97,7 +90,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty),
|
||||
_ => bug!("drop method is not a TyFnDef"),
|
||||
};
|
||||
let fn_ptr = self.memory.create_fn_ptr(drop_def_id, substs, fn_ty);
|
||||
let fn_ptr = self.memory.create_fn_ptr(self.tcx, drop_def_id, substs, fn_ty);
|
||||
self.memory.write_ptr(vtable, fn_ptr)?;
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use std::{fmt, iter, ptr};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::{BareFnTy, ClosureTy, ClosureSubsts};
|
||||
use rustc::ty::{self, BareFnTy, ClosureTy, ClosureSubsts, TyCtxt};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::layout::{self, TargetDataLayout};
|
||||
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use primval::PrimVal;
|
||||
|
||||
@ -88,19 +90,9 @@ impl Pointer {
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
struct FunctionDefinition<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub kind: FunctionKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
enum FunctionKind<'tcx> {
|
||||
Closure {
|
||||
substs: ClosureSubsts<'tcx>,
|
||||
ty: ClosureTy<'tcx>,
|
||||
},
|
||||
Function {
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
ty: &'tcx BareFnTy<'tcx>,
|
||||
}
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
pub abi: Abi,
|
||||
pub sig: &'tcx ty::FnSig<'tcx>,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -143,23 +135,31 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
self.alloc_map.iter()
|
||||
}
|
||||
|
||||
pub fn create_closure_ptr(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer {
|
||||
pub fn create_closure_ptr(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer {
|
||||
// FIXME: this is a hack
|
||||
let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
|
||||
unsafety: fn_ty.unsafety,
|
||||
abi: fn_ty.abi,
|
||||
sig: fn_ty.sig,
|
||||
});
|
||||
self.create_fn_alloc(FunctionDefinition {
|
||||
def_id: def_id,
|
||||
kind: FunctionKind::Closure {
|
||||
substs: substs,
|
||||
ty: fn_ty,
|
||||
}
|
||||
substs: substs.func_substs,
|
||||
abi: fn_ty.abi,
|
||||
// FIXME: why doesn't this compile?
|
||||
//sig: tcx.erase_late_bound_regions(&fn_ty.sig),
|
||||
sig: fn_ty.sig.skip_binder(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
|
||||
pub fn create_fn_ptr(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
|
||||
self.create_fn_alloc(FunctionDefinition {
|
||||
def_id: def_id,
|
||||
kind: FunctionKind::Function {
|
||||
substs: substs,
|
||||
ty: fn_ty,
|
||||
}
|
||||
substs: substs,
|
||||
abi: fn_ty.abi,
|
||||
// FIXME: why doesn't this compile?
|
||||
//sig: tcx.erase_late_bound_regions(&fn_ty.sig),
|
||||
sig: fn_ty.sig.skip_binder(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -308,33 +308,15 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_closure(&self, id: AllocId) -> EvalResult<'tcx, (DefId, ClosureSubsts<'tcx>, ClosureTy<'tcx>)> {
|
||||
debug!("reading closure fn ptr: {}", id);
|
||||
match self.functions.get(&id) {
|
||||
Some(&FunctionDefinition {
|
||||
def_id,
|
||||
kind: FunctionKind::Closure { ref substs, ref ty }
|
||||
}) => Ok((def_id, *substs, ty.clone())),
|
||||
Some(&FunctionDefinition {
|
||||
kind: FunctionKind::Function { .. }, ..
|
||||
}) => Err(EvalError::CalledClosureAsFunction),
|
||||
None => match self.alloc_map.get(&id) {
|
||||
Some(_) => Err(EvalError::ExecuteMemory),
|
||||
None => Err(EvalError::InvalidFunctionPointer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>)> {
|
||||
pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, Abi, &'tcx ty::FnSig<'tcx>)> {
|
||||
debug!("reading fn ptr: {}", id);
|
||||
match self.functions.get(&id) {
|
||||
Some(&FunctionDefinition {
|
||||
def_id,
|
||||
kind: FunctionKind::Function { substs, ty }
|
||||
}) => Ok((def_id, substs, ty)),
|
||||
Some(&FunctionDefinition {
|
||||
kind: FunctionKind::Closure { .. }, ..
|
||||
}) => Err(EvalError::CalledClosureAsFunction),
|
||||
substs,
|
||||
abi,
|
||||
sig,
|
||||
}) => Ok((def_id, substs, abi, sig)),
|
||||
None => match self.alloc_map.get(&id) {
|
||||
Some(_) => Err(EvalError::ExecuteMemory),
|
||||
None => Err(EvalError::InvalidFunctionPointer),
|
||||
|
@ -5,5 +5,5 @@ fn main() {
|
||||
std::mem::transmute::<fn(), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR tried to call a function of type
|
||||
g(42) //~ ERROR tried to call a function with abi Rust and sig
|
||||
}
|
||||
|
25
tests/run-pass/last-use-in-cap-clause.rs
Normal file
25
tests/run-pass/last-use-in-cap-clause.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Make sure #1399 stays fixed
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct A { a: Box<isize> }
|
||||
|
||||
fn foo() -> Box<FnMut() -> isize + 'static> {
|
||||
let k: Box<_> = Box::new(22);
|
||||
let _u = A {a: k.clone()};
|
||||
let result = || 22;
|
||||
Box::new(result)
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(foo()(), 22);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user