Skip to content

Commit d5e4471

Browse files
authored
Merge pull request rust-lang#58 from oli-obk/master
only split the Fn* arguments in case of closures and function pointers
2 parents 07b8500 + 21e9249 commit d5e4471

File tree

3 files changed

+65
-22
lines changed

3 files changed

+65
-22
lines changed

src/interpreter/terminator/mod.rs

+21-22
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
178178
}
179179

180180
Abi::Rust | Abi::RustCall => {
181-
// TODO(solson): Adjust the first argument when calling a Fn or
182-
// FnMut closure via FnOnce::call_once.
183-
184181
let mut arg_srcs = Vec::new();
185182
for arg in args {
186183
let src = self.eval_operand_to_ptr(arg)?;
@@ -196,25 +193,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
196193
(def_id, substs)
197194
};
198195

199-
if fn_ty.abi == Abi::RustCall {
200-
if let Some((last, last_ty)) = arg_srcs.pop() {
201-
let last_layout = self.type_layout(last_ty);
202-
match (&last_ty.sty, last_layout) {
203-
(&ty::TyTuple(fields),
204-
&Layout::Univariant { ref variant, .. }) => {
205-
let offsets = iter::once(0)
206-
.chain(variant.offset_after_field.iter()
207-
.map(|s| s.bytes()));
208-
for (offset, ty) in offsets.zip(fields) {
209-
let src = last.offset(offset as isize);
210-
arg_srcs.push((src, ty));
211-
}
212-
}
213-
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
214-
}
215-
}
216-
}
217-
218196
let mir = self.load_mir(resolved_def_id);
219197
let (return_ptr, return_to_block) = match destination {
220198
Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)),
@@ -366,6 +344,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
366344
})
367345
}
368346

347+
fn unpack_fn_args(&self, args: &mut Vec<(Pointer, Ty<'tcx>)>) {
348+
if let Some((last, last_ty)) = args.pop() {
349+
let last_layout = self.type_layout(last_ty);
350+
match (&last_ty.sty, last_layout) {
351+
(&ty::TyTuple(fields),
352+
&Layout::Univariant { ref variant, .. }) => {
353+
let offsets = iter::once(0)
354+
.chain(variant.offset_after_field.iter()
355+
.map(|s| s.bytes()));
356+
for (offset, ty) in offsets.zip(fields) {
357+
let src = last.offset(offset as isize);
358+
args.push((src, ty));
359+
}
360+
}
361+
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
362+
}
363+
}
364+
}
365+
369366
/// Trait method, which has to be resolved to an impl method.
370367
fn trait_method(
371368
&mut self,
@@ -395,6 +392,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
395392
.expect("The substitutions should have no type parameters remaining after passing through fulfill_obligation");
396393
let closure_kind = self.tcx.closure_kind(vtable_closure.closure_def_id);
397394
trace!("closures {:?}, {:?}", closure_kind, trait_closure_kind);
395+
self.unpack_fn_args(args);
398396
match (closure_kind, trait_closure_kind) {
399397
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
400398
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
@@ -426,6 +424,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
426424
traits::VtableFnPointer(vtable_fn_ptr) => {
427425
if let ty::TyFnDef(did, ref substs, _) = vtable_fn_ptr.fn_ty.sty {
428426
args.remove(0);
427+
self.unpack_fn_args(args);
429428
Ok((did, substs))
430429
} else {
431430
bug!("VtableFnPointer did not contain a concrete function: {:?}", vtable_fn_ptr)

tests/run-pass/function_pointers.rs

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ fn g(i: i32) -> i32 {
66
i*42
77
}
88

9+
fn h(i: i32, j: i32) -> i32 {
10+
j * i * 7
11+
}
12+
913
fn return_fn_ptr() -> fn() -> i32 {
1014
f
1115
}
@@ -22,6 +26,10 @@ fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
2226
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
2327
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }
2428

29+
fn indirect3<F: Fn(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
30+
fn indirect_mut3<F: FnMut(i32, i32) -> i32>(mut f: F) -> i32 { f(10, 3) }
31+
fn indirect_once3<F: FnOnce(i32, i32) -> i32>(f: F) -> i32 { f(10, 3) }
32+
2533
fn main() {
2634
assert_eq!(call_fn_ptr(), 42);
2735
assert_eq!(indirect(f), 42);
@@ -30,6 +38,9 @@ fn main() {
3038
assert_eq!(indirect2(g), 420);
3139
assert_eq!(indirect_mut2(g), 420);
3240
assert_eq!(indirect_once2(g), 420);
41+
assert_eq!(indirect3(h), 210);
42+
assert_eq!(indirect_mut3(h), 210);
43+
assert_eq!(indirect_once3(h), 210);
3344
assert!(return_fn_ptr() == f);
3445
assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
3546
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
12+
#![feature(lang_items, unboxed_closures, fn_traits)]
13+
14+
struct S3 {
15+
x: i32,
16+
y: i32,
17+
}
18+
19+
impl FnOnce<(i32,i32)> for S3 {
20+
type Output = i32;
21+
extern "rust-call" fn call_once(self, (z,zz): (i32,i32)) -> i32 {
22+
self.x * self.y * z * zz
23+
}
24+
}
25+
26+
fn main() {
27+
let s = S3 {
28+
x: 3,
29+
y: 3,
30+
};
31+
let ans = s(3, 1);
32+
assert_eq!(ans, 27);
33+
}

0 commit comments

Comments
 (0)