diff --git a/src/error.rs b/src/error.rs index 8001d95941e..481815996a0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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) => diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 6697dcd60e6..ee503f97d78 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -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) | diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs index fbd9e76a07f..ccf7671eec2 100644 --- a/src/interpreter/terminator/mod.rs +++ b/src/interpreter/terminator/mod.rs @@ -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 { diff --git a/src/interpreter/vtable.rs b/src/interpreter/vtable.rs index 201bedc1a86..6651194be7d 100644 --- a/src/interpreter/vtable.rs +++ b/src/interpreter/vtable.rs @@ -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::>() .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)?; } } diff --git a/src/memory.rs b/src/memory.rs index 8bb39d5167f..fce0ff4c976 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -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), diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index e9b2536a700..c8070913f1c 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function of type + g(42) //~ ERROR tried to call a function with abi Rust and sig } diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/run-pass/last-use-in-cap-clause.rs new file mode 100644 index 00000000000..de2d815ca54 --- /dev/null +++ b/tests/run-pass/last-use-in-cap-clause.rs @@ -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 or the MIT license +// , 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 } + +fn foo() -> Box 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); +}