use std::error::Error;
use std::fmt;
use rustc::mir;
-use rustc::ty::{BareFnTy, Ty, FnSig, layout};
-use syntax::abi::Abi;
+use rustc::ty::{PolyFnSig, Ty, layout};
use memory::{Pointer, Function};
use rustc_const_math::ConstMathErr;
use syntax::codemap::Span;
#[derive(Clone, Debug)]
pub enum EvalError<'tcx> {
- FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
+ FunctionPointerTyMismatch(PolyFnSig<'tcx>, PolyFnSig<'tcx>),
NoMirFor(String),
UnterminatedCString(Pointer),
DanglingPointerDeref,
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
},
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
- 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::FunctionPointerTyMismatch(sig, got) =>
+ write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig.skip_binder(), got.skip_binder()),
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) =>
Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
- Float(ConstFloat::FInfer { .. }) =>
- bug!("uninferred constants only exist before typeck"),
Bool(b) => PrimVal::from_bool(b),
Char(c) => PrimVal::from_char(c),
Struct(_) => unimplemented!(),
Tuple(_) => unimplemented!(),
- Function(_) => unimplemented!(),
+ Function(_, _) => unimplemented!(),
Array(_) => unimplemented!(),
Repeat(_, _) => unimplemented!(),
};
General { discr, ref variants, .. } => {
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
- let discr_val = adt_def.variants[variant].disr_val;
+ let discr_val = adt_def.discriminants(self.tcx)
+ .nth(variant)
+ .expect("broken mir: Adt variant id invalid")
+ .to_u128_unchecked();
let discr_size = discr.size().bytes();
if variants[variant].packed {
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
CEnum { .. } => {
assert_eq!(operands.len(), 0);
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
- let n = adt_def.variants[variant].disr_val;
+ let n = adt_def.discriminants(self.tcx)
+ .nth(variant)
+ .expect("broken mir: Adt variant index invalid")
+ .to_u128_unchecked();
self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
} else {
bug!("tried to assign {:?} to Layout::CEnum", kind);
}
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(self.tcx,def_id, substs, fn_ty);
+ ty::TyFnDef(def_id, substs, sig) => {
+ let fn_ptr = self.memory.create_fn_ptr(def_id, substs, sig);
self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("reify fn pointer 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);
+ let fn_ty = self.tcx.closure_type(def_id);
+ let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(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),
let ptr = self.force_allocation(lval)?.to_ptr();
let discr_val = self.read_discriminant_value(ptr, ty)?;
if let ty::TyAdt(adt_def, _) = ty.sty {
- if adt_def.variants.iter().all(|v| discr_val != v.disr_val) {
+ if adt_def.discriminants(self.tcx).all(|v| discr_val != v.to_u128_unchecked()) {
return Err(EvalError::InvalidDiscriminant);
}
} else {
use std::{fmt, iter, ptr, mem, io};
use rustc::hir::def_id::DefId;
-use rustc::ty::{self, BareFnTy, ClosureTy, ClosureSubsts, TyCtxt};
+use rustc::ty::{self, PolyFnSig, ClosureSubsts};
use rustc::ty::subst::Substs;
use rustc::ty::layout::{self, TargetDataLayout};
-use syntax::abi::Abi;
-
use error::{EvalError, EvalResult};
use value::PrimVal;
pub struct FunctionDefinition<'tcx> {
pub def_id: DefId,
pub substs: &'tcx Substs<'tcx>,
- pub abi: Abi,
- pub sig: &'tcx ty::FnSig<'tcx>,
+ pub sig: PolyFnSig<'tcx>,
}
/// Either a concrete function, or a glue function
DropGlue(ty::Ty<'tcx>),
/// Glue required to treat the ptr part of a fat pointer
/// as a function pointer
- FnPtrAsTraitObject(&'tcx ty::FnSig<'tcx>),
+ FnPtrAsTraitObject(PolyFnSig<'tcx>),
/// Glue for Closures
Closure(FunctionDefinition<'tcx>),
/// Glue for noncapturing closures casted to function pointers
self.alloc_map.iter()
}
- 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,
- });
+ pub fn create_closure_ptr(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer {
self.create_fn_alloc(Function::Closure(FunctionDefinition {
def_id,
substs: 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(),
+ sig,
}))
}
- 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,
- });
+ pub fn create_fn_ptr_from_noncapture_closure(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer {
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(),
+ sig,
}))
}
- 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 {
+ pub fn create_fn_as_trait_glue(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer {
self.create_fn_alloc(Function::FnDefAsTraitObject(FunctionDefinition {
def_id,
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(),
+ sig,
}))
}
- pub fn create_fn_ptr_as_trait_glue(&mut self, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
- self.create_fn_alloc(Function::FnPtrAsTraitObject(fn_ty.sig.skip_binder()))
+ pub fn create_fn_ptr_as_trait_glue(&mut self, sig: PolyFnSig<'tcx>) -> Pointer {
+ self.create_fn_alloc(Function::FnPtrAsTraitObject(sig))
}
pub fn create_drop_glue(&mut self, ty: ty::Ty<'tcx>) -> Pointer {
self.create_fn_alloc(Function::DropGlue(ty))
}
- 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 {
+ pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer {
self.create_fn_alloc(Function::Concrete(FunctionDefinition {
def_id,
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(),
+ sig,
}))
}
fn dump_fn_def<'tcx>(fn_def: FunctionDefinition<'tcx>) -> String {
let name = ty::tls::with(|tcx| tcx.item_path_str(fn_def.def_id));
- let abi = if fn_def.abi == Abi::Rust {
- format!("")
- } else {
- format!("extern {} ", fn_def.abi)
- };
- format!("function pointer: {}: {}{}", name, abi, fn_def.sig)
+ format!("function pointer: {}: {}", name, fn_def.sig.skip_binder())
}
/// Byte accessors
let (adt_ptr, extra) = lval.to_ptr_and_extra();
// run drop impl before the fields' drop impls
- if let Some(drop_def_id) = adt_def.destructor() {
+ if let Some(drop_def_id) = adt_def.destructor(self.tcx) {
let trait_ref = ty::Binder(ty::TraitRef {
def_id: self.tcx.lang_items.drop_trait().unwrap(),
substs: self.tcx.mk_substs_trait(ty, &[]),
Layout::General { .. } => {
let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
let ptr = self.force_allocation(lval)?.to_ptr();
- match adt_def.variants.iter().position(|v| discr_val == v.disr_val) {
+ match adt_def.discriminants(self.tcx).position(|v| discr_val == v.to_u128_unchecked()) {
Some(i) => {
lval = Lvalue::Ptr {
ptr,
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty};
+use rustc_const_math::ConstInt;
use syntax::codemap::Span;
use syntax::attr;
+use syntax::abi::Abi;
use error::{EvalError, EvalResult};
use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited};
let func_ty = self.operand_ty(func);
let fn_def = match func_ty.sty {
- ty::TyFnPtr(bare_fn_ty) => {
+ ty::TyFnPtr(bare_sig) => {
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
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);
match fn_def {
Function::Concrete(fn_def) => {
// transmuting function pointers in miri is fine as long as the number of
// 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));
+ if fn_def.sig.abi() != bare_sig.abi() ||
+ fn_def.sig.variadic() != bare_sig.variadic() ||
+ fn_def.sig.inputs().skip_binder().len() != bare_sig.inputs().skip_binder().len() {
+ return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
}
},
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));
+ assert_eq!(fn_def.sig.abi(), Abi::RustCall);
+ if fn_def.sig.variadic() != bare_sig.variadic() ||
+ fn_def.sig.inputs().skip_binder().len() != 1 {
+ return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
}
- 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));
+ if let ty::TyTuple(fields, _) = fn_def.sig.inputs().skip_binder()[0].sty {
+ if fields.len() != bare_sig.inputs().skip_binder().len() {
+ return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
}
}
},
ty::TyFnDef(def_id, substs, fn_ty) => Function::Concrete(FunctionDefinition {
def_id,
substs,
- abi: fn_ty.abi,
- sig: fn_ty.sig.skip_binder(),
+ sig: fn_ty,
}),
_ => {
use syntax::abi::Abi;
match fn_def {
// Intrinsics can only be addressed directly
- Function::Concrete(FunctionDefinition { def_id, substs, abi: Abi::RustIntrinsic, sig }) => {
- let ty = sig.output();
+ Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => {
+ let ty = *sig.output().skip_binder();
let layout = self.type_layout(ty)?;
let (ret, target) = match destination {
Some(dest) if is_inhabited(self.tcx, ty) => dest,
Ok(())
},
// C functions can only be addressed directly
- Function::Concrete(FunctionDefinition { def_id, abi: Abi::C, sig, ..}) => {
- let ty = sig.output();
+ Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => {
+ let ty = *sig.output().skip_binder();
let (ret, target) = destination.unwrap();
self.call_c_abi(def_id, arg_operands, ret, ty)?;
self.dump_local(ret);
Ok(())
},
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 }) => {
+ Function::Concrete(FunctionDefinition { def_id, sig, substs }) if sig.abi() == Abi::Rust || sig.abi() == Abi::RustCall => {
let mut args = Vec::new();
for arg in arg_operands {
let arg_val = self.eval_operand(arg)?;
};
// FIXME(eddyb) Detect ADT constructors more efficiently.
- 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) {
+ if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() {
+ let dids = adt_def.variants.iter().map(|v| v.did);
+ let discrs = adt_def.discriminants(self.tcx).map(ConstInt::to_u128_unchecked);
+ if let Some((_, disr_val)) = dids.zip(discrs).find(|&(did, _)| resolved_def_id == did) {
let (lvalue, target) = destination.expect("tuple struct constructors can't diverge");
let dest_ty = self.tcx.item_type(adt_def.did);
let dest_layout = self.type_layout(dest_ty)?;
trace!("layout({:?}) = {:#?}", dest_ty, dest_layout);
match *dest_layout {
Layout::Univariant { .. } => {
- let disr_val = v.disr_val;
assert_eq!(disr_val, 0);
self.assign_fields(lvalue, dest_ty, args)?;
},
Layout::General { discr, ref variants, .. } => {
- let disr_val = v.disr_val;
let discr_size = discr.size().bytes();
self.assign_discr_and_fields(
lvalue,
)?;
},
Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
- let disr_val = v.disr_val;
if nndiscr as u128 == disr_val {
self.assign_fields(lvalue, dest_ty, args)?;
} else {
span,
)
},
- Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, abi: Abi::Rust, substs, sig }) => {
+ Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => {
let mut args = Vec::new();
for arg in arg_operands {
let arg_val = self.eval_operand(arg)?;
}
args.insert(0, (
Value::ByVal(PrimVal::Undef),
- sig.inputs()[0],
+ sig.inputs().skip_binder()[0],
));
self.eval_fn_call_inner(
def_id,
match self.memory.get_fn(fn_ptr.alloc_id)? {
Function::FnDefAsTraitObject(fn_def) => {
trace!("sig: {:#?}", fn_def.sig);
- assert!(fn_def.abi != abi::Abi::RustCall);
+ assert!(fn_def.sig.abi() != abi::Abi::RustCall);
assert_eq!(args.len(), 2);
// a function item turned into a closure trait object
// the first arg is just there to give use the vtable
trace!("sig: {:#?}", fn_def.sig);
args[0] = (
Value::ByVal(PrimVal::Ptr(self_ptr)),
- fn_def.sig.inputs()[0],
+ fn_def.sig.inputs().skip_binder()[0],
);
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],
+ fn_def.sig.inputs().skip_binder()[0],
));
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],
+ fn_def.sig.inputs().skip_binder()[0],
));
fn_def
},
_ => bug!("bad function type: {}", fn_ty),
};
let fn_ty = self.tcx.erase_regions(&fn_ty);
- self.memory.create_fn_ptr(self.tcx, mth.method.def_id, mth.substs, fn_ty)
+ self.memory.create_fn_ptr(mth.method.def_id, mth.substs, fn_ty)
}))
.collect::<Vec<_>>()
.into_iter()
..
}
) => {
- let closure_type = self.tcx.closure_type(closure_def_id, substs);
- vec![Some(self.memory.create_closure_ptr(self.tcx, closure_def_id, substs, closure_type))].into_iter()
+ let closure_type = self.tcx.closure_type(closure_def_id);
+ vec![Some(self.memory.create_closure_ptr(closure_def_id, substs, closure_type))].into_iter()
}
// turn a function definition into a Fn trait object
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, .. }) => {
match fn_ty.sty {
ty::TyFnDef(did, substs, bare_fn_ty) => {
- vec![Some(self.memory.create_fn_as_trait_glue(self.tcx, did, substs, bare_fn_ty))].into_iter()
+ vec![Some(self.memory.create_fn_as_trait_glue(did, substs, bare_fn_ty))].into_iter()
},
ty::TyFnPtr(bare_fn_ty) => {
vec![Some(self.memory.create_fn_ptr_as_trait_glue(bare_fn_ty))].into_iter()
// in case there is no drop function to be called, this still needs to be initialized
self.memory.write_usize(vtable, 0)?;
if let ty::TyAdt(adt_def, substs) = trait_ref.self_ty().sty {
- if let Some(drop_def_id) = adt_def.destructor() {
+ if let Some(drop_def_id) = adt_def.destructor(self.tcx) {
let fn_ty = match self.tcx.item_type(drop_def_id).sty {
ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty),
_ => bug!("drop method is not a TyFnDef"),
};
// The real type is taken from the self argument in `fn drop(&mut self)`
- let real_ty = match fn_ty.sig.skip_binder().inputs()[0].sty {
+ let real_ty = match fn_ty.inputs().skip_binder()[0].sty {
ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs),
_ => bug!("first argument of Drop::drop must be &mut T"),
};
std::mem::transmute::<fn(), fn(i32)>(f)
};
- g(42) //~ ERROR tried to call a function with abi Rust and sig
+ g(42) //~ ERROR tried to call a function with sig fn() through a function pointer of type fn(i32)
}