Skip to content

Commit 0391af0

Browse files
Only unpack tupled args in inliner if we expect args to be unpacked
1 parent 2fd4c28 commit 0391af0

File tree

4 files changed

+89
-12
lines changed

4 files changed

+89
-12
lines changed

compiler/rustc_mir_transform/src/inline.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -222,20 +222,23 @@ impl<'tcx> Inliner<'tcx> {
222222
trace!(?output_type, ?destination_ty);
223223
return Err("failed to normalize return type");
224224
}
225-
if callsite.fn_sig.abi() == Abi::RustCall {
226-
let (arg_tuple, skipped_args) = match &args[..] {
227-
[arg_tuple] => (arg_tuple, 0),
228-
[_, arg_tuple] => (arg_tuple, 1),
225+
if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() {
226+
let (self_arg, arg_tuple) = match &args[..] {
227+
[arg_tuple] => (None, arg_tuple),
228+
[self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
229229
_ => bug!("Expected `rust-call` to have 1 or 2 args"),
230230
};
231231

232+
let self_arg_ty =
233+
self_arg.map(|self_arg| self_arg.ty(&caller_body.local_decls, self.tcx));
234+
232235
let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx);
233-
let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else {
236+
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
234237
bug!("Closure arguments are not passed as a tuple");
235238
};
236239

237240
for (arg_ty, input) in
238-
arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
241+
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
239242
{
240243
let input_type = callee_body.local_decls[input].ty;
241244
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
- // MIR for `call` before Inline
2+
+ // MIR for `call` after Inline
3+
4+
fn call(_1: Box<dyn FnMut<I, Output = ()>>, _2: I) -> () {
5+
debug mock => _1;
6+
debug input => _2;
7+
let mut _0: ();
8+
let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
9+
let mut _4: I;
10+
+ scope 1 (inlined <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut) {
11+
+ debug self => _3;
12+
+ debug args => _4;
13+
+ let mut _5: &mut dyn std::ops::FnMut<I, Output = ()>;
14+
+ let mut _6: std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
15+
+ let mut _7: *const dyn std::ops::FnMut<I, Output = ()>;
16+
+ }
17+
18+
bb0: {
19+
StorageLive(_3);
20+
_3 = &mut _1;
21+
StorageLive(_4);
22+
_4 = move _2;
23+
- _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
24+
+ StorageLive(_5);
25+
+ _6 = deref_copy (*_3);
26+
+ _7 = (((_6.0: std::ptr::Unique<dyn std::ops::FnMut<I, Output = ()>>).0: std::ptr::NonNull<dyn std::ops::FnMut<I, Output = ()>>).0: *const dyn std::ops::FnMut<I, Output = ()>);
27+
+ _5 = &mut (*_7);
28+
+ _0 = <dyn FnMut<I, Output = ()> as FnMut<I>>::call_mut(move _5, move _4) -> [return: bb2, unwind unreachable];
29+
}
30+
31+
bb1: {
32+
- StorageDead(_4);
33+
- StorageDead(_3);
34+
- drop(_1) -> [return: bb2, unwind unreachable];
35+
+ return;
36+
}
37+
38+
bb2: {
39+
- return;
40+
+ StorageDead(_5);
41+
+ StorageDead(_4);
42+
+ StorageDead(_3);
43+
+ drop(_1) -> [return: bb1, unwind unreachable];
44+
}
45+
}
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib
2+
3+
#![feature(fn_traits, tuple_trait, unboxed_closures)]
4+
5+
use std::marker::Tuple;
6+
7+
// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
8+
pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
9+
mock.call_mut(input)
10+
}

tests/mir-opt/inline/inline_box_fn.call.Inline.diff

+24-6
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,44 @@
77
let _2: ();
88
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
99
let mut _4: (i32,);
10+
+ scope 1 (inlined <Box<dyn Fn(i32)> as Fn<(i32,)>>::call) {
11+
+ debug self => _3;
12+
+ debug args => _4;
13+
+ let mut _5: &dyn std::ops::Fn(i32);
14+
+ let mut _6: std::boxed::Box<dyn std::ops::Fn(i32)>;
15+
+ let mut _7: *const dyn std::ops::Fn(i32);
16+
+ }
1017

1118
bb0: {
1219
StorageLive(_2);
1320
StorageLive(_3);
1421
_3 = &_1;
1522
StorageLive(_4);
1623
_4 = (const 1_i32,);
17-
_2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
24+
- _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
25+
+ StorageLive(_5);
26+
+ _6 = deref_copy (*_3);
27+
+ _7 = (((_6.0: std::ptr::Unique<dyn std::ops::Fn(i32)>).0: std::ptr::NonNull<dyn std::ops::Fn(i32)>).0: *const dyn std::ops::Fn(i32));
28+
+ _5 = &(*_7);
29+
+ _2 = <dyn Fn(i32) as Fn<(i32,)>>::call(move _5, move _4) -> [return: bb2, unwind unreachable];
1830
}
1931

2032
bb1: {
33+
+ return;
34+
+ }
35+
+
36+
+ bb2: {
37+
+ StorageDead(_5);
2138
StorageDead(_4);
2239
StorageDead(_3);
2340
StorageDead(_2);
2441
_0 = const ();
25-
drop(_1) -> [return: bb2, unwind unreachable];
26-
}
27-
28-
bb2: {
29-
return;
42+
- drop(_1) -> [return: bb2, unwind unreachable];
43+
- }
44+
-
45+
- bb2: {
46+
- return;
47+
+ drop(_1) -> [return: bb1, unwind unreachable];
3048
}
3149
}
3250

0 commit comments

Comments
 (0)