Skip to content

Commit fd68670

Browse files
committed
merge closures and function and implement some closure vtable cases
1 parent 64155ff commit fd68670

File tree

7 files changed

+75
-77
lines changed

7 files changed

+75
-77
lines changed

src/error.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use std::error::Error;
22
use std::fmt;
33
use rustc::mir;
4-
use rustc::ty::{BareFnTy, Ty};
4+
use rustc::ty::{BareFnTy, Ty, FnSig};
5+
use syntax::abi::Abi;
56
use memory::Pointer;
67
use rustc_const_math::ConstMathErr;
78
use syntax::codemap::Span;
89

910
#[derive(Clone, Debug)]
1011
pub enum EvalError<'tcx> {
11-
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
12+
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
1213
NoMirFor(String),
1314
DanglingPointerDeref,
1415
InvalidMemoryAccess,
@@ -123,8 +124,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
123124
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
124125
},
125126
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
126-
EvalError::FunctionPointerTyMismatch(expected, got) =>
127-
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
127+
EvalError::FunctionPointerTyMismatch(abi, sig, got) =>
128+
write!(f, "tried to call a function with abi {:?} and sig {:?} through a function pointer of type {:?}", abi, sig, got),
128129
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
129130
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
130131
EvalError::Math(span, ref err) =>

src/interpreter/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
666666
ReifyFnPointer => match self.operand_ty(operand).sty {
667667
ty::TyFnDef(def_id, substs, fn_ty) => {
668668
let fn_ty = self.tcx.erase_regions(&fn_ty);
669-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
669+
let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
670670
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
671671
},
672672
ref other => bug!("reify fn pointer on {:?}", other),
@@ -676,9 +676,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
676676
ty::TyFnPtr(unsafe_fn_ty) => {
677677
let src = self.eval_operand(operand)?;
678678
let ptr = src.read_ptr(&self.memory)?;
679-
let (def_id, substs, _) = self.memory.get_fn(ptr.alloc_id)?;
679+
let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
680680
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
681-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, unsafe_fn_ty);
681+
let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty);
682682
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
683683
},
684684
ref other => bug!("fn to unsafe fn cast on {:?}", other),
@@ -1403,8 +1403,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
14031403
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
14041404

14051405
ty::TyFnDef(def_id, substs, fn_ty) => {
1406-
let fn_ty = self.tcx.erase_regions(&fn_ty);
1407-
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(def_id, substs, fn_ty))
1406+
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
14081407
},
14091408
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_fn_ptr)?,
14101409
ty::TyBox(ty) |

src/interpreter/terminator/mod.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
8686
match func_ty.sty {
8787
ty::TyFnPtr(bare_fn_ty) => {
8888
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
89-
let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
90-
if fn_ty != bare_fn_ty {
91-
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
89+
let (def_id, substs, abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
90+
if abi != bare_fn_ty.abi || sig != bare_fn_ty.sig.skip_binder() {
91+
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty));
9292
}
9393
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
9494
terminator.source_info.span)?
@@ -500,9 +500,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
500500
let idx = idx + 3;
501501
let offset = idx * self.memory.pointer_size();
502502
let fn_ptr = self.memory.read_ptr(vtable.offset(offset as isize))?;
503-
let (def_id, substs, ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
504-
// FIXME: skip_binder is wrong for HKL
505-
*first_ty = ty.sig.skip_binder().inputs[0];
503+
let (def_id, substs, _abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
504+
*first_ty = sig.inputs[0];
506505
Ok((def_id, substs))
507506
} else {
508507
Err(EvalError::VtableForArgumentlessMethod)
@@ -643,9 +642,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
643642
let drop_fn = self.memory.read_ptr(vtable)?;
644643
// some values don't need to call a drop impl, so the value is null
645644
if drop_fn != Pointer::from_int(0) {
646-
let (def_id, substs, ty) = self.memory.get_fn(drop_fn.alloc_id)?;
647-
let fn_sig = self.tcx.erase_late_bound_regions_and_normalize(&ty.sig);
648-
let real_ty = fn_sig.inputs[0];
645+
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?;
646+
let real_ty = sig.inputs[0];
649647
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
650648
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs));
651649
} else {

src/interpreter/vtable.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
3636
.into_iter()
3737
.map(|opt_mth| opt_mth.map(|mth| {
3838
let fn_ty = self.tcx.erase_regions(&mth.method.fty);
39-
self.memory.create_fn_ptr(mth.method.def_id, mth.substs, fn_ty)
39+
self.memory.create_fn_ptr(self.tcx, mth.method.def_id, mth.substs, fn_ty)
4040
}))
4141
.collect::<Vec<_>>()
4242
.into_iter()
@@ -47,22 +47,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
4747
substs,
4848
nested: _ }) => {
4949
let closure_type = self.tcx.closure_type(closure_def_id, substs);
50-
let fn_ty = ty::BareFnTy {
51-
unsafety: closure_type.unsafety,
52-
abi: closure_type.abi,
53-
sig: closure_type.sig,
54-
};
55-
let _fn_ty = self.tcx.mk_bare_fn(fn_ty);
56-
unimplemented!()
57-
//vec![Some(self.memory.create_fn_ptr(closure_def_id, substs.func_substs, fn_ty))].into_iter()
50+
vec![Some(self.memory.create_closure_ptr(self.tcx, closure_def_id, substs, closure_type))].into_iter()
5851
}
5952
traits::VtableFnPointer(
6053
traits::VtableFnPointerData {
6154
fn_ty,
6255
nested: _ }) => {
6356
match fn_ty.sty {
6457
ty::TyFnDef(did, substs, bare_fn_ty) => {
65-
vec![Some(self.memory.create_fn_ptr(did, substs, bare_fn_ty))].into_iter()
58+
vec![Some(self.memory.create_fn_ptr(self.tcx, did, substs, bare_fn_ty))].into_iter()
6659
},
6760
_ => bug!("bad VtableFnPointer fn_ty: {:?}", fn_ty),
6861
}
@@ -97,7 +90,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9790
ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty),
9891
_ => bug!("drop method is not a TyFnDef"),
9992
};
100-
let fn_ptr = self.memory.create_fn_ptr(drop_def_id, substs, fn_ty);
93+
let fn_ptr = self.memory.create_fn_ptr(self.tcx, drop_def_id, substs, fn_ty);
10194
self.memory.write_ptr(vtable, fn_ptr)?;
10295
}
10396
}

src/memory.rs

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
44
use std::{fmt, iter, ptr};
55

66
use rustc::hir::def_id::DefId;
7-
use rustc::ty::{BareFnTy, ClosureTy, ClosureSubsts};
7+
use rustc::ty::{self, BareFnTy, ClosureTy, ClosureSubsts, TyCtxt};
88
use rustc::ty::subst::Substs;
99
use rustc::ty::layout::{self, TargetDataLayout};
1010

11+
use syntax::abi::Abi;
12+
1113
use error::{EvalError, EvalResult};
1214
use primval::PrimVal;
1315

@@ -88,19 +90,9 @@ impl Pointer {
8890
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
8991
struct FunctionDefinition<'tcx> {
9092
pub def_id: DefId,
91-
pub kind: FunctionKind<'tcx>,
92-
}
93-
94-
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
95-
enum FunctionKind<'tcx> {
96-
Closure {
97-
substs: ClosureSubsts<'tcx>,
98-
ty: ClosureTy<'tcx>,
99-
},
100-
Function {
101-
substs: &'tcx Substs<'tcx>,
102-
ty: &'tcx BareFnTy<'tcx>,
103-
}
93+
pub substs: &'tcx Substs<'tcx>,
94+
pub abi: Abi,
95+
pub sig: &'tcx ty::FnSig<'tcx>,
10496
}
10597

10698
////////////////////////////////////////////////////////////////////////////////
@@ -143,23 +135,31 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
143135
self.alloc_map.iter()
144136
}
145137

146-
pub fn create_closure_ptr(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer {
138+
pub fn create_closure_ptr(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer {
139+
// FIXME: this is a hack
140+
let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
141+
unsafety: fn_ty.unsafety,
142+
abi: fn_ty.abi,
143+
sig: fn_ty.sig,
144+
});
147145
self.create_fn_alloc(FunctionDefinition {
148146
def_id: def_id,
149-
kind: FunctionKind::Closure {
150-
substs: substs,
151-
ty: fn_ty,
152-
}
147+
substs: substs.func_substs,
148+
abi: fn_ty.abi,
149+
// FIXME: why doesn't this compile?
150+
//sig: tcx.erase_late_bound_regions(&fn_ty.sig),
151+
sig: fn_ty.sig.skip_binder(),
153152
})
154153
}
155154

156-
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
155+
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 {
157156
self.create_fn_alloc(FunctionDefinition {
158157
def_id: def_id,
159-
kind: FunctionKind::Function {
160-
substs: substs,
161-
ty: fn_ty,
162-
}
158+
substs: substs,
159+
abi: fn_ty.abi,
160+
// FIXME: why doesn't this compile?
161+
//sig: tcx.erase_late_bound_regions(&fn_ty.sig),
162+
sig: fn_ty.sig.skip_binder(),
163163
})
164164
}
165165

@@ -308,33 +308,15 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
308308
}
309309
}
310310

311-
pub fn get_closure(&self, id: AllocId) -> EvalResult<'tcx, (DefId, ClosureSubsts<'tcx>, ClosureTy<'tcx>)> {
312-
debug!("reading closure fn ptr: {}", id);
313-
match self.functions.get(&id) {
314-
Some(&FunctionDefinition {
315-
def_id,
316-
kind: FunctionKind::Closure { ref substs, ref ty }
317-
}) => Ok((def_id, *substs, ty.clone())),
318-
Some(&FunctionDefinition {
319-
kind: FunctionKind::Function { .. }, ..
320-
}) => Err(EvalError::CalledClosureAsFunction),
321-
None => match self.alloc_map.get(&id) {
322-
Some(_) => Err(EvalError::ExecuteMemory),
323-
None => Err(EvalError::InvalidFunctionPointer),
324-
}
325-
}
326-
}
327-
328-
pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>)> {
311+
pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, Abi, &'tcx ty::FnSig<'tcx>)> {
329312
debug!("reading fn ptr: {}", id);
330313
match self.functions.get(&id) {
331314
Some(&FunctionDefinition {
332315
def_id,
333-
kind: FunctionKind::Function { substs, ty }
334-
}) => Ok((def_id, substs, ty)),
335-
Some(&FunctionDefinition {
336-
kind: FunctionKind::Closure { .. }, ..
337-
}) => Err(EvalError::CalledClosureAsFunction),
316+
substs,
317+
abi,
318+
sig,
319+
}) => Ok((def_id, substs, abi, sig)),
338320
None => match self.alloc_map.get(&id) {
339321
Some(_) => Err(EvalError::ExecuteMemory),
340322
None => Err(EvalError::InvalidFunctionPointer),

tests/compile-fail/cast_fn_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ fn main() {
55
std::mem::transmute::<fn(), fn(i32)>(f)
66
};
77

8-
g(42) //~ ERROR tried to call a function of type
8+
g(42) //~ ERROR tried to call a function with abi Rust and sig
99
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Make sure #1399 stays fixed
12+
13+
#[allow(dead_code)]
14+
struct A { a: Box<isize> }
15+
16+
fn foo() -> Box<FnMut() -> isize + 'static> {
17+
let k: Box<_> = Box::new(22);
18+
let _u = A {a: k.clone()};
19+
let result = || 22;
20+
Box::new(result)
21+
}
22+
23+
pub fn main() {
24+
assert_eq!(foo()(), 22);
25+
}

0 commit comments

Comments
 (0)