Skip to content

Commit 1c82e60

Browse files
committed
auto merge of #18113 : bkoropoff/rust/issue-16739, r=alexcrichton
When translating the unboxing shim, account for the fact that the shim translation has already performed the necessary unboxing of input types and values when forwarding to the shimmed function. This prevents ICEing or generating incorrect code. Closes #16739
2 parents ce342f5 + f4cb9f4 commit 1c82e60

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

src/librustc/middle/trans/callee.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,32 @@ pub fn trans_unboxing_shim(bcx: Block,
281281
};
282282
let boxed_function_type =
283283
ty::mk_bare_fn(tcx, boxed_function_type).subst(tcx, &substs);
284-
let function_type =
285-
ty::mk_bare_fn(tcx, (*fty).clone()).subst(tcx, &substs);
284+
let function_type = match fty.abi {
285+
synabi::RustCall => {
286+
// We're passing through to a RustCall ABI function, but
287+
// because the shim will already perform untupling, we
288+
// need to pretend the shimmed function does not use
289+
// RustCall so the untupled arguments can be passed
290+
// through verbatim. This is kind of ugly.
291+
let fake_ty = ty::FnSig {
292+
binder_id: fty.sig.binder_id,
293+
inputs: type_of::untuple_arguments_if_necessary(ccx,
294+
fty.sig.inputs.as_slice(),
295+
fty.abi),
296+
output: fty.sig.output,
297+
variadic: false,
298+
};
299+
let fake_ty = ty::BareFnTy {
300+
fn_style: fty.fn_style,
301+
abi: synabi::Rust,
302+
sig: fake_ty,
303+
};
304+
ty::mk_bare_fn(tcx, fake_ty).subst(tcx, &substs)
305+
}
306+
_ => {
307+
ty::mk_bare_fn(tcx, (*fty).clone()).subst(tcx, &substs)
308+
}
309+
};
286310

287311
let function_name = ty::with_path(tcx, method_id, |path| {
288312
link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim")

src/librustc/middle/trans/type_of.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
5858
/// Yields the types of the "real" arguments for this function. For most
5959
/// functions, these are simply the types of the arguments. For functions with
6060
/// the `RustCall` ABI, however, this untuples the arguments of the function.
61-
fn untuple_arguments_if_necessary(ccx: &CrateContext,
62-
inputs: &[ty::t],
63-
abi: abi::Abi)
64-
-> Vec<ty::t> {
61+
pub fn untuple_arguments_if_necessary(ccx: &CrateContext,
62+
inputs: &[ty::t],
63+
abi: abi::Abi)
64+
-> Vec<ty::t> {
6565
if abi != abi::RustCall {
6666
return inputs.iter().map(|x| (*x).clone()).collect()
6767
}

src/test/run-pass/issue-16739.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2014 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+
#![feature(unboxed_closures)]
12+
13+
// Test that unboxing shim for calling rust-call ABI methods through a
14+
// trait box works and does not cause an ICE
15+
16+
struct Foo { foo: uint }
17+
18+
impl FnOnce<(), uint> for Foo {
19+
#[rust_call_abi_hack]
20+
fn call_once(self, _: ()) -> uint { self.foo }
21+
}
22+
23+
impl FnOnce<(uint,), uint> for Foo {
24+
#[rust_call_abi_hack]
25+
fn call_once(self, (x,): (uint,)) -> uint { self.foo + x }
26+
}
27+
28+
impl FnOnce<(uint, uint), uint> for Foo {
29+
#[rust_call_abi_hack]
30+
fn call_once(self, (x, y): (uint, uint)) -> uint { self.foo + x + y }
31+
}
32+
33+
fn main() {
34+
let f = box Foo { foo: 42 } as Box<FnOnce<(), uint>>;
35+
assert_eq!(f.call_once(()), 42);
36+
37+
let f = box Foo { foo: 40 } as Box<FnOnce<(uint,), uint>>;
38+
assert_eq!(f.call_once((2,)), 42);
39+
40+
let f = box Foo { foo: 40 } as Box<FnOnce<(uint, uint), uint>>;
41+
assert_eq!(f.call_once((1, 1)), 42);
42+
}

0 commit comments

Comments
 (0)