Skip to content

Commit 60fa393

Browse files
committed
Auto merge of rust-lang#110833 - compiler-errors:rustc-call-inliner-ice, r=cjgillot
Only unpack tupled args in inliner if we expect args to be unpacked `"rust-call"` is a strange function abi. sometimes, it expects the arguments to be unpacked by the caller and passed as individual args (closure bodies), and sometimes it does not (user functions annotated with the `"rust-call"` abi). make sure the mir inliner respects this difference when checking that arguments are compatible, and doesn't try to ICE when we call a `extern "rust-call"` function in a generic context. fixes rust-lang#110829
2 parents 1fe3846 + e43649f commit 60fa393

17 files changed

+255
-159
lines changed

compiler/rustc_mir_transform/src/inline.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -223,19 +223,29 @@ impl<'tcx> Inliner<'tcx> {
223223
return Err("failed to normalize return type");
224224
}
225225
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),
226+
// FIXME: Don't inline user-written `extern "rust-call"` functions,
227+
// since this is generally perf-negative on rustc, and we hope that
228+
// LLVM will inline these functions instead.
229+
if callee_body.spread_arg.is_some() {
230+
return Err("do not inline user-written rust-call functions");
231+
}
232+
233+
let (self_arg, arg_tuple) = match &args[..] {
234+
[arg_tuple] => (None, arg_tuple),
235+
[self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
229236
_ => bug!("Expected `rust-call` to have 1 or 2 args"),
230237
};
231238

239+
let self_arg_ty =
240+
self_arg.map(|self_arg| self_arg.ty(&caller_body.local_decls, self.tcx));
241+
232242
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 {
243+
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
234244
bug!("Closure arguments are not passed as a tuple");
235245
};
236246

237247
for (arg_ty, input) in
238-
arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
248+
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
239249
{
240250
let input_type = callee_body.local_decls[input].ty;
241251
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {

tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff

+1-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
let mut _0: ();
66
let _1: ();
77
+ let mut _2: fn() {main};
8-
+ let mut _5: ();
98
+ scope 1 (inlined f::<fn() {main}>) {
109
+ debug g => _2;
1110
+ let mut _3: &fn() {main};
1211
+ let _4: ();
13-
+ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
14-
+ }
1512
+ }
1613

1714
bb0: {
@@ -22,9 +19,7 @@
2219
+ StorageLive(_4);
2320
+ StorageLive(_3);
2421
+ _3 = &_2;
25-
+ StorageLive(_5);
26-
+ _5 = const ();
27-
+ _4 = move (*_3)() -> [return: bb2, unwind unreachable];
22+
+ _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind unreachable];
2823
}
2924

3025
bb1: {
@@ -36,7 +31,6 @@
3631
+ }
3732
+
3833
+ bb2: {
39-
+ StorageDead(_5);
4034
+ StorageDead(_3);
4135
+ drop(_2) -> [return: bb1, unwind unreachable];
4236
}

tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff

+7-13
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
let mut _0: ();
66
let _1: ();
77
+ let mut _2: fn() {main};
8-
+ let mut _5: ();
98
+ scope 1 (inlined f::<fn() {main}>) {
109
+ debug g => _2;
1110
+ let mut _3: &fn() {main};
1211
+ let _4: ();
13-
+ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
14-
+ }
1512
+ }
1613

1714
bb0: {
@@ -22,9 +19,7 @@
2219
+ StorageLive(_4);
2320
+ StorageLive(_3);
2421
+ _3 = &_2;
25-
+ StorageLive(_5);
26-
+ _5 = const ();
27-
+ _4 = move (*_3)() -> [return: bb4, unwind: bb2];
22+
+ _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind: bb3];
2823
}
2924

3025
bb1: {
@@ -35,18 +30,17 @@
3530
return;
3631
+ }
3732
+
38-
+ bb2 (cleanup): {
39-
+ drop(_2) -> [return: bb3, unwind terminate];
33+
+ bb2: {
34+
+ StorageDead(_3);
35+
+ drop(_2) -> [return: bb1, unwind continue];
4036
+ }
4137
+
4238
+ bb3 (cleanup): {
43-
+ resume;
39+
+ drop(_2) -> [return: bb4, unwind terminate];
4440
+ }
4541
+
46-
+ bb4: {
47-
+ StorageDead(_5);
48-
+ StorageDead(_3);
49-
+ drop(_2) -> [return: bb1, unwind continue];
42+
+ bb4 (cleanup): {
43+
+ resume;
5044
}
5145
}
5246

tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff

+1-17
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,10 @@
55
let mut _0: ();
66
let _1: ();
77
+ let mut _2: fn() {g};
8-
+ let mut _5: ();
98
+ scope 1 (inlined f::<fn() {g}>) {
109
+ debug g => _2;
1110
+ let mut _3: &fn() {g};
1211
+ let _4: ();
13-
+ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) {
14-
+ scope 3 (inlined g) {
15-
+ scope 4 (inlined f::<fn() {main}>) {
16-
+ debug g => main;
17-
+ let _6: ();
18-
+ scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
19-
+ }
20-
+ }
21-
+ }
22-
+ }
2312
+ }
2413

2514
bb0: {
@@ -30,10 +19,7 @@
3019
+ StorageLive(_4);
3120
+ StorageLive(_3);
3221
+ _3 = &_2;
33-
+ StorageLive(_5);
34-
+ _5 = const ();
35-
+ StorageLive(_6);
36-
+ _6 = main() -> [return: bb2, unwind unreachable];
22+
+ _4 = <fn() {g} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind unreachable];
3723
}
3824

3925
bb1: {
@@ -45,8 +31,6 @@
4531
+ }
4632
+
4733
+ bb2: {
48-
+ StorageDead(_6);
49-
+ StorageDead(_5);
5034
+ StorageDead(_3);
5135
+ drop(_2) -> [return: bb1, unwind unreachable];
5236
}

tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff

+7-23
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,10 @@
55
let mut _0: ();
66
let _1: ();
77
+ let mut _2: fn() {g};
8-
+ let mut _5: ();
98
+ scope 1 (inlined f::<fn() {g}>) {
109
+ debug g => _2;
1110
+ let mut _3: &fn() {g};
1211
+ let _4: ();
13-
+ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) {
14-
+ scope 3 (inlined g) {
15-
+ scope 4 (inlined f::<fn() {main}>) {
16-
+ debug g => main;
17-
+ let _6: ();
18-
+ scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
19-
+ }
20-
+ }
21-
+ }
22-
+ }
2312
+ }
2413

2514
bb0: {
@@ -30,10 +19,7 @@
3019
+ StorageLive(_4);
3120
+ StorageLive(_3);
3221
+ _3 = &_2;
33-
+ StorageLive(_5);
34-
+ _5 = const ();
35-
+ StorageLive(_6);
36-
+ _6 = main() -> [return: bb4, unwind: bb2];
22+
+ _4 = <fn() {g} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind: bb3];
3723
}
3824

3925
bb1: {
@@ -44,19 +30,17 @@
4430
return;
4531
+ }
4632
+
47-
+ bb2 (cleanup): {
48-
+ drop(_2) -> [return: bb3, unwind terminate];
33+
+ bb2: {
34+
+ StorageDead(_3);
35+
+ drop(_2) -> [return: bb1, unwind continue];
4936
+ }
5037
+
5138
+ bb3 (cleanup): {
52-
+ resume;
39+
+ drop(_2) -> [return: bb4, unwind terminate];
5340
+ }
5441
+
55-
+ bb4: {
56-
+ StorageDead(_6);
57-
+ StorageDead(_5);
58-
+ StorageDead(_3);
59-
+ drop(_2) -> [return: bb1, unwind continue];
42+
+ bb4 (cleanup): {
43+
+ resume;
6044
}
6145
}
6246

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
11+
bb0: {
12+
StorageLive(_3);
13+
_3 = &mut _1;
14+
StorageLive(_4);
15+
_4 = move _2;
16+
_0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
17+
}
18+
19+
bb1: {
20+
StorageDead(_4);
21+
StorageDead(_3);
22+
drop(_1) -> [return: bb2, unwind unreachable];
23+
}
24+
25+
bb2: {
26+
return;
27+
}
28+
}
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
11+
bb0: {
12+
StorageLive(_3);
13+
_3 = &mut _1;
14+
StorageLive(_4);
15+
_4 = move _2;
16+
_0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind: bb3];
17+
}
18+
19+
bb1: {
20+
StorageDead(_4);
21+
StorageDead(_3);
22+
drop(_1) -> [return: bb2, unwind: bb4];
23+
}
24+
25+
bb2: {
26+
return;
27+
}
28+
29+
bb3 (cleanup): {
30+
drop(_1) -> [return: bb4, unwind terminate];
31+
}
32+
33+
bb4 (cleanup): {
34+
resume;
35+
}
36+
}
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
2+
// compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib
3+
4+
#![feature(fn_traits, tuple_trait, unboxed_closures)]
5+
6+
use std::marker::Tuple;
7+
8+
// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
9+
pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
10+
mock.call_mut(input)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- // MIR for `call` before Inline
2+
+ // MIR for `call` after Inline
3+
4+
fn call(_1: Box<dyn Fn(i32)>) -> () {
5+
debug x => _1;
6+
let mut _0: ();
7+
let _2: ();
8+
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
9+
let mut _4: (i32,);
10+
11+
bb0: {
12+
StorageLive(_2);
13+
StorageLive(_3);
14+
_3 = &_1;
15+
StorageLive(_4);
16+
_4 = (const 1_i32,);
17+
_2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
18+
}
19+
20+
bb1: {
21+
StorageDead(_4);
22+
StorageDead(_3);
23+
StorageDead(_2);
24+
_0 = const ();
25+
drop(_1) -> [return: bb2, unwind unreachable];
26+
}
27+
28+
bb2: {
29+
return;
30+
}
31+
}
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
- // MIR for `call` before Inline
2+
+ // MIR for `call` after Inline
3+
4+
fn call(_1: Box<dyn Fn(i32)>) -> () {
5+
debug x => _1;
6+
let mut _0: ();
7+
let _2: ();
8+
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
9+
let mut _4: (i32,);
10+
11+
bb0: {
12+
StorageLive(_2);
13+
StorageLive(_3);
14+
_3 = &_1;
15+
StorageLive(_4);
16+
_4 = (const 1_i32,);
17+
_2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind: bb3];
18+
}
19+
20+
bb1: {
21+
StorageDead(_4);
22+
StorageDead(_3);
23+
StorageDead(_2);
24+
_0 = const ();
25+
drop(_1) -> [return: bb2, unwind: bb4];
26+
}
27+
28+
bb2: {
29+
return;
30+
}
31+
32+
bb3 (cleanup): {
33+
drop(_1) -> [return: bb4, unwind terminate];
34+
}
35+
36+
bb4 (cleanup): {
37+
resume;
38+
}
39+
}
40+

tests/mir-opt/inline/inline_box_fn.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
2+
// unit-test: Inline
3+
// compile-flags: --crate-type=lib
4+
5+
// EMIT_MIR inline_box_fn.call.Inline.diff
6+
fn call(x: Box<dyn Fn(i32)>) {
7+
x(1);
8+
}

0 commit comments

Comments
 (0)