提交 8878a403 编写于 作者: O Oliver Schneider

rustup to rustc 1.17.0-nightly (60a0edc6 2017-02-26)

上级 feeb13c4
......@@ -649,16 +649,21 @@ pub(super) fn eval_rvalue_into_lvalue(
},
UnsafeFnPointer => match dest_ty.sty {
ty::TyFnPtr(unsafe_fn_ty) => {
ty::TyFnPtr(_) => {
let src = self.eval_operand(operand)?;
let ptr = src.read_ptr(&self.memory)?;
let fn_def = self.memory.get_fn(ptr.alloc_id)?.expect_concrete()?;
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
let fn_ptr = self.memory.create_fn_ptr(self.tcx, fn_def.def_id, fn_def.substs, unsafe_fn_ty);
self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
self.write_value(src, dest, dest_ty)?;
},
ref other => bug!("fn to unsafe fn cast on {:?}", other),
},
ClosureFnPointer => match self.operand_ty(operand).sty {
ty::TyClosure(def_id, substs) => {
let fn_ty = self.tcx.closure_type(def_id, substs);
let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(self.tcx, def_id, substs, fn_ty);
self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("reify fn pointer on {:?}", other),
},
}
}
......
......@@ -130,15 +130,11 @@ pub enum Function<'tcx> {
FnPtrAsTraitObject(&'tcx ty::FnSig<'tcx>),
/// Glue for Closures
Closure(FunctionDefinition<'tcx>),
/// Glue for noncapturing closures casted to function pointers
NonCaptureClosureAsFnPtr(FunctionDefinition<'tcx>),
}
impl<'tcx> Function<'tcx> {
pub fn expect_concrete(self) -> EvalResult<'tcx, FunctionDefinition<'tcx>> {
match self {
Function::Concrete(fn_def) => Ok(fn_def),
other => Err(EvalError::ExpectedConcreteFunction(other)),
}
}
pub fn expect_drop_glue_real_ty(self) -> EvalResult<'tcx, ty::Ty<'tcx>> {
match self {
Function::DropGlue(real_ty) => Ok(real_ty),
......@@ -238,6 +234,23 @@ pub fn create_closure_ptr(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId,
}))
}
pub fn create_fn_ptr_from_noncapture_closure(&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(Function::NonCaptureClosureAsFnPtr(FunctionDefinition {
def_id,
substs: substs.substs,
abi: Abi::Rust, // adjust 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_as_trait_glue(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
self.create_fn_alloc(Function::FnDefAsTraitObject(FunctionDefinition {
def_id,
......@@ -535,6 +548,10 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
trace!("{} closure glue for {}", msg, dump_fn_def(fn_def));
continue;
},
(None, Some(&Function::NonCaptureClosureAsFnPtr(fn_def))) => {
trace!("{} non-capture closure as fn ptr glue for {}", msg, dump_fn_def(fn_def));
continue;
},
(None, None) => {
trace!("{} (deallocated)", msg);
continue;
......
......@@ -2,14 +2,14 @@
use rustc::mir;
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, BareFnTy};
use rustc::ty::{self, Ty};
use syntax::codemap::Span;
use syntax::attr;
use error::{EvalError, EvalResult};
use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited};
use lvalue::Lvalue;
use memory::{Pointer, FunctionDefinition};
use memory::{Pointer, FunctionDefinition, Function};
use value::PrimVal;
use value::Value;
......@@ -61,35 +61,54 @@ pub(super) fn eval_terminator(
};
let func_ty = self.operand_ty(func);
match func_ty.sty {
let fn_def = match func_ty.sty {
ty::TyFnPtr(bare_fn_ty) => {
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
let FunctionDefinition {def_id, substs, abi, sig} = self.memory.get_fn(fn_ptr.alloc_id)?.expect_concrete()?;
let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?;
let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig);
let bare_sig = self.tcx.erase_regions(&bare_sig);
// transmuting function pointers in miri is fine as long as the number of
// arguments and the abi don't change.
// FIXME: also check the size of the arguments' type and the return type
// Didn't get it to work, since that triggers an assertion in rustc which
// checks whether the type has escaping regions
if abi != bare_fn_ty.abi ||
sig.variadic != bare_sig.variadic ||
sig.inputs().len() != bare_sig.inputs().len() {
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty));
match fn_def {
Function::Concrete(fn_def) => {
// transmuting function pointers in miri is fine as long as the number of
// arguments and the abi don't change.
// FIXME: also check the size of the arguments' type and the return type
// Didn't get it to work, since that triggers an assertion in rustc which
// checks whether the type has escaping regions
if fn_def.abi != bare_fn_ty.abi ||
fn_def.sig.variadic != bare_sig.variadic ||
fn_def.sig.inputs().len() != bare_sig.inputs().len() {
return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty));
}
},
Function::NonCaptureClosureAsFnPtr(fn_def) => {
if fn_def.abi != bare_fn_ty.abi ||
fn_def.sig.variadic != bare_sig.variadic ||
fn_def.sig.inputs().len() != 1 {
return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty));
}
if let ty::TyTuple(fields, _) = fn_def.sig.inputs()[0].sty {
if fields.len() != bare_sig.inputs().len() {
return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty));
}
}
},
other => return Err(EvalError::ExpectedConcreteFunction(other)),
}
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
terminator.source_info.span)?
self.memory.get_fn(fn_ptr.alloc_id)?
},
ty::TyFnDef(def_id, substs, fn_ty) => {
self.eval_fn_call(def_id, substs, fn_ty, destination, args,
terminator.source_info.span)?
}
ty::TyFnDef(def_id, substs, fn_ty) => Function::Concrete(FunctionDefinition {
def_id,
substs,
abi: fn_ty.abi,
sig: fn_ty.sig.skip_binder(),
}),
_ => {
let msg = format!("can't handle callee of type {:?}", func_ty);
return Err(EvalError::Unimplemented(msg));
}
}
};
self.eval_fn_call(fn_def, destination, args, terminator.source_info.span)?;
}
Drop { ref location, target, .. } => {
......@@ -138,17 +157,16 @@ pub(super) fn eval_terminator(
fn eval_fn_call(
&mut self,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
fn_ty: &'tcx BareFnTy,
fn_def: Function<'tcx>,
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
arg_operands: &[mir::Operand<'tcx>],
span: Span,
) -> EvalResult<'tcx> {
use syntax::abi::Abi;
match fn_ty.abi {
Abi::RustIntrinsic => {
let ty = fn_ty.sig.0.output();
match fn_def {
// Intrinsics can only be addressed directly
Function::Concrete(FunctionDefinition { def_id, substs, abi: Abi::RustIntrinsic, sig }) => {
let ty = sig.output();
let layout = self.type_layout(ty)?;
let (ret, target) = match destination {
Some(dest) if is_inhabited(self.tcx, ty) => dest,
......@@ -157,18 +175,19 @@ fn eval_fn_call(
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?;
self.dump_local(ret);
Ok(())
}
Abi::C => {
let ty = fn_ty.sig.0.output();
},
// C functions can only be addressed directly
Function::Concrete(FunctionDefinition { def_id, abi: Abi::C, sig, ..}) => {
let ty = sig.output();
let (ret, target) = destination.unwrap();
self.call_c_abi(def_id, arg_operands, ret, ty)?;
self.dump_local(ret);
self.goto_block(target);
Ok(())
}
Abi::Rust | Abi::RustCall => {
},
Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue),
Function::Concrete(FunctionDefinition { def_id, abi: Abi::RustCall, sig, substs }) |
Function::Concrete(FunctionDefinition { def_id, abi: Abi::Rust, sig, substs }) => {
let mut args = Vec::new();
for arg in arg_operands {
let arg_val = self.eval_operand(arg)?;
......@@ -185,7 +204,7 @@ fn eval_fn_call(
};
// FIXME(eddyb) Detect ADT constructors more efficiently.
if let Some(adt_def) = fn_ty.sig.skip_binder().output().ty_adt_def() {
if let Some(adt_def) = sig.output().ty_adt_def() {
if let Some(v) = adt_def.variants.iter().find(|v| resolved_def_id == v.did) {
let (lvalue, target) = destination.expect("tuple struct constructors can't diverge");
let dest_ty = self.tcx.item_type(adt_def.did);
......@@ -240,66 +259,105 @@ fn eval_fn_call(
return Ok(());
}
}
let mir = match self.load_mir(resolved_def_id) {
Ok(mir) => mir,
Err(EvalError::NoMirFor(path)) => {
match &path[..] {
// let's just ignore all output for now
"std::io::_print" => {
self.goto_block(destination.unwrap().1);
return Ok(());
},
"std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
"std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
"std::panicking::rust_panic_with_hook" |
"std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
"std::panicking::panicking" |
"std::rt::panicking" => {
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
// we abort on panic -> `std::rt::panicking` always returns false
let bool = self.tcx.types.bool;
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
self.goto_block(block);
return Ok(());
}
_ => {},
}
return Err(EvalError::NoMirFor(path));
},
Err(other) => return Err(other),
};
let (return_lvalue, return_to_block) = match destination {
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
None => {
// FIXME(solson)
let lvalue = Lvalue::from_ptr(Pointer::never_ptr());
(lvalue, StackPopCleanup::None)
}
};
self.push_stack_frame(
self.eval_fn_call_inner(
resolved_def_id,
span,
mir,
resolved_substs,
return_lvalue,
return_to_block,
destination,
args,
temporaries,
)?;
let arg_locals = self.frame().mir.args_iter();
assert_eq!(self.frame().mir.arg_count, args.len());
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
self.write_value(arg_val, dest, arg_ty)?;
span,
)
},
Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, abi: Abi::Rust, substs, sig }) => {
let mut args = Vec::new();
for arg in arg_operands {
let arg_val = self.eval_operand(arg)?;
let arg_ty = self.operand_ty(arg);
args.push((arg_val, arg_ty));
}
args.insert(0, (
Value::ByVal(PrimVal::Undef),
sig.inputs()[0],
));
self.eval_fn_call_inner(
def_id,
substs,
destination,
args,
Vec::new(),
span,
)
}
other => Err(EvalError::Unimplemented(format!("can't call function kind {:?}", other))),
}
}
Ok(())
fn eval_fn_call_inner(
&mut self,
resolved_def_id: DefId,
resolved_substs: &'tcx Substs,
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
args: Vec<(Value, Ty<'tcx>)>,
temporaries: Vec<(Pointer, Ty<'tcx>)>,
span: Span,
) -> EvalResult<'tcx> {
trace!("eval_fn_call_inner: {:#?}, {:#?}, {:#?}", args, temporaries, destination);
let mir = match self.load_mir(resolved_def_id) {
Ok(mir) => mir,
Err(EvalError::NoMirFor(path)) => {
match &path[..] {
// let's just ignore all output for now
"std::io::_print" => {
self.goto_block(destination.unwrap().1);
return Ok(());
},
"std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
"std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
"std::panicking::rust_panic_with_hook" |
"std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
"std::panicking::panicking" |
"std::rt::panicking" => {
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
// we abort on panic -> `std::rt::panicking` always returns false
let bool = self.tcx.types.bool;
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
self.goto_block(block);
return Ok(());
}
_ => {},
}
return Err(EvalError::NoMirFor(path));
},
Err(other) => return Err(other),
};
let (return_lvalue, return_to_block) = match destination {
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
None => {
// FIXME(solson)
let lvalue = Lvalue::from_ptr(Pointer::never_ptr());
(lvalue, StackPopCleanup::None)
}
};
abi => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
self.push_stack_frame(
resolved_def_id,
span,
mir,
resolved_substs,
return_lvalue,
return_to_block,
temporaries,
)?;
let arg_locals = self.frame().mir.args_iter();
assert_eq!(self.frame().mir.arg_count, args.len());
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
self.write_value(arg_val, dest, arg_ty)?;
}
Ok(())
}
pub fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
......
......@@ -130,6 +130,13 @@ pub(crate) fn trait_method(
);
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
},
Function::NonCaptureClosureAsFnPtr(fn_def) => {
args.insert(0, (
Value::ByVal(PrimVal::Undef),
fn_def.sig.inputs()[0],
));
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
}
Function::Closure(fn_def) => {
self.unpack_fn_args(args)?;
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
......@@ -140,8 +147,20 @@ pub(crate) fn trait_method(
args.remove(0);
self.unpack_fn_args(args)?;
let fn_ptr = self.memory.read_ptr(self_ptr)?;
let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?.expect_concrete()?;
assert_eq!(sig, fn_def.sig);
let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? {
Function::Concrete(fn_def) => {
assert_eq!(sig, fn_def.sig);
fn_def
},
Function::NonCaptureClosureAsFnPtr(fn_def) => {
args.insert(0, (
Value::ByVal(PrimVal::Undef),
fn_def.sig.inputs()[0],
));
fn_def
},
other => bug!("FnPtrAsTraitObject for {:?}", other),
};
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
}
}
......
#![feature(closure_to_fn_coercion)]
// allow(const_err) to work around a bug in warnings
#[allow(const_err)]
static FOO: fn() = || { assert_ne!(42, 43) };
#[allow(const_err)]
static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) };
fn main() {
FOO();
BAR(44, 45);
let bar: unsafe fn(i32, i32) = BAR;
unsafe { bar(46, 47) };
let boo: &Fn(i32, i32) = &BAR;
boo(48, 49);
}
#![feature(static_recursion)]
struct S(&'static S);
static S1: S = S(&S2);
static S2: S = S(&S1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册