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:
commit
d5e44712a4
3 changed files with 65 additions and 22 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
33
tests/run-pass/overloaded-calls-simple.rs
Normal file
33
tests/run-pass/overloaded-calls-simple.rs
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue