Merge pull request #58 from oli-obk/master

only split the Fn* arguments in case of closures and function pointers
This commit is contained in:
Scott Olson 2016-09-21 08:16:08 -06:00 committed by GitHub
commit d5e44712a4
3 changed files with 65 additions and 22 deletions

View file

@ -178,9 +178,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
Abi::Rust | Abi::RustCall => {
// TODO(solson): Adjust the first argument when calling a Fn or
// FnMut closure via FnOnce::call_once.
let mut arg_srcs = Vec::new();
for arg in args {
let src = self.eval_operand_to_ptr(arg)?;
@ -196,25 +193,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
(def_id, substs)
};
if fn_ty.abi == Abi::RustCall {
if let Some((last, last_ty)) = arg_srcs.pop() {
let last_layout = self.type_layout(last_ty);
match (&last_ty.sty, last_layout) {
(&ty::TyTuple(fields),
&Layout::Univariant { ref variant, .. }) => {
let offsets = iter::once(0)
.chain(variant.offset_after_field.iter()
.map(|s| s.bytes()));
for (offset, ty) in offsets.zip(fields) {
let src = last.offset(offset as isize);
arg_srcs.push((src, ty));
}
}
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
}
}
}
let mir = self.load_mir(resolved_def_id);
let (return_ptr, return_to_block) = match destination {
Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)),
@ -366,6 +344,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
})
}
fn unpack_fn_args(&self, args: &mut Vec<(Pointer, Ty<'tcx>)>) {
if let Some((last, last_ty)) = args.pop() {
let last_layout = self.type_layout(last_ty);
match (&last_ty.sty, last_layout) {
(&ty::TyTuple(fields),
&Layout::Univariant { ref variant, .. }) => {
let offsets = iter::once(0)
.chain(variant.offset_after_field.iter()
.map(|s| s.bytes()));
for (offset, ty) in offsets.zip(fields) {
let src = last.offset(offset as isize);
args.push((src, ty));
}
}
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
}
}
}
/// Trait method, which has to be resolved to an impl method.
fn trait_method(
&mut self,
@ -395,6 +392,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
.expect("The substitutions should have no type parameters remaining after passing through fulfill_obligation");
let closure_kind = self.tcx.closure_kind(vtable_closure.closure_def_id);
trace!("closures {:?}, {:?}", closure_kind, trait_closure_kind);
self.unpack_fn_args(args);
match (closure_kind, trait_closure_kind) {
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
@ -426,6 +424,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
traits::VtableFnPointer(vtable_fn_ptr) => {
if let ty::TyFnDef(did, ref substs, _) = vtable_fn_ptr.fn_ty.sty {
args.remove(0);
self.unpack_fn_args(args);
Ok((did, substs))
} else {
bug!("VtableFnPointer did not contain a concrete function: {:?}", vtable_fn_ptr)

View file

@ -6,6 +6,10 @@ fn g(i: i32) -> i32 {
i*42
}
fn h(i: i32, j: i32) -> i32 {
j * i * 7
}
fn return_fn_ptr() -> fn() -> i32 {
f
}
@ -22,6 +26,10 @@ fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }
fn indirect3<F: Fn(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
fn indirect_mut3<F: FnMut(i32, i32) -> i32>(mut f: F) -> i32 { f(10, 3) }
fn indirect_once3<F: FnOnce(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
fn main() {
assert_eq!(call_fn_ptr(), 42);
assert_eq!(indirect(f), 42);
@ -30,6 +38,9 @@ fn main() {
assert_eq!(indirect2(g), 420);
assert_eq!(indirect_mut2(g), 420);
assert_eq!(indirect_once2(g), 420);
assert_eq!(indirect3(h), 210);
assert_eq!(indirect_mut3(h), 210);
assert_eq!(indirect_once3(h), 210);
assert!(return_fn_ptr() == f);
assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
}

View file

@ -0,0 +1,33 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(lang_items, unboxed_closures, fn_traits)]
struct S3 {
x: i32,
y: i32,
}
impl FnOnce<(i32,i32)> for S3 {
type Output = i32;
extern "rust-call" fn call_once(self, (z,zz): (i32,i32)) -> i32 {
self.x * self.y * z * zz
}
}
fn main() {
let s = S3 {
x: 3,
y: 3,
};
let ans = s(3, 1);
assert_eq!(ans, 27);
}