rustup to rustc 1.17.0-nightly (60a0edc6c 2017-02-26)
This commit is contained in:
parent
feeb13c4b9
commit
8878a4030a
@ -649,16 +649,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
},
|
||||
|
||||
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 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
}))
|
||||
}
|
||||
|
||||
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 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
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::hir::def_id::DefId;
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
// 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,68 +259,107 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
args.insert(0, (
|
||||
Value::ByVal(PrimVal::Undef),
|
||||
sig.inputs()[0],
|
||||
));
|
||||
self.eval_fn_call_inner(
|
||||
def_id,
|
||||
substs,
|
||||
destination,
|
||||
args,
|
||||
Vec::new(),
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
abi => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
|
||||
other => Err(EvalError::Unimplemented(format!("can't call function kind {:?}", other))),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
||||
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> {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
let adt_layout = self.type_layout(adt_ty)?;
|
||||
|
@ -130,6 +130,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
);
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
16
tests/run-pass/non_capture_closure_to_fn_ptr.rs
Normal file
16
tests/run-pass/non_capture_closure_to_fn_ptr.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![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);
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
#![feature(static_recursion)]
|
||||
|
||||
struct S(&'static S);
|
||||
static S1: S = S(&S2);
|
||||
static S2: S = S(&S1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user