about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs15
-rw-r--r--tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff46
-rw-r--r--tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs10
-rw-r--r--tests/mir-opt/inline/inline_box_fn.call.Inline.diff30
4 files changed, 89 insertions, 12 deletions
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f13c8214af1..8abd549c588 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -222,20 +222,23 @@ impl<'tcx> Inliner<'tcx> {
             trace!(?output_type, ?destination_ty);
             return Err("failed to normalize return type");
         }
-        if callsite.fn_sig.abi() == Abi::RustCall {
-            let (arg_tuple, skipped_args) = match &args[..] {
-                [arg_tuple] => (arg_tuple, 0),
-                [_, arg_tuple] => (arg_tuple, 1),
+        if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() {
+            let (self_arg, arg_tuple) = match &args[..] {
+                [arg_tuple] => (None, arg_tuple),
+                [self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
                 _ => bug!("Expected `rust-call` to have 1 or 2 args"),
             };
 
+            let self_arg_ty =
+                self_arg.map(|self_arg| self_arg.ty(&caller_body.local_decls, self.tcx));
+
             let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx);
-            let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else {
+            let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
                 bug!("Closure arguments are not passed as a tuple");
             };
 
             for (arg_ty, input) in
-                arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
+                self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
             {
                 let input_type = callee_body.local_decls[input].ty;
                 if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff
new file mode 100644
index 00000000000..c665d779e61
--- /dev/null
+++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.diff
@@ -0,0 +1,46 @@
+- // MIR for `call` before Inline
++ // MIR for `call` after Inline
+  
+  fn call(_1: Box<dyn FnMut<I, Output = ()>>, _2: I) -> () {
+      debug mock => _1;
+      debug input => _2;
+      let mut _0: ();
+      let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
+      let mut _4: I;
++     scope 1 (inlined <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut) {
++         debug self => _3;
++         debug args => _4;
++         let mut _5: &mut dyn std::ops::FnMut<I, Output = ()>;
++         let mut _6: std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
++         let mut _7: *const dyn std::ops::FnMut<I, Output = ()>;
++     }
+  
+      bb0: {
+          StorageLive(_3);
+          _3 = &mut _1;
+          StorageLive(_4);
+          _4 = move _2;
+-         _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
++         StorageLive(_5);
++         _6 = deref_copy (*_3);
++         _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 = ()>);
++         _5 = &mut (*_7);
++         _0 = <dyn FnMut<I, Output = ()> as FnMut<I>>::call_mut(move _5, move _4) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb1: {
+-         StorageDead(_4);
+-         StorageDead(_3);
+-         drop(_1) -> [return: bb2, unwind unreachable];
++         return;
+      }
+  
+      bb2: {
+-         return;
++         StorageDead(_5);
++         StorageDead(_4);
++         StorageDead(_3);
++         drop(_1) -> [return: bb1, unwind unreachable];
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs
new file mode 100644
index 00000000000..f00e99c27e4
--- /dev/null
+++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib
+
+#![feature(fn_traits, tuple_trait, unboxed_closures)]
+
+use std::marker::Tuple;
+
+// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
+pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
+    mock.call_mut(input)
+}
diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff
index 4fa04b05e89..34ac637af8a 100644
--- a/tests/mir-opt/inline/inline_box_fn.call.Inline.diff
+++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.diff
@@ -7,6 +7,13 @@
       let _2: ();
       let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
       let mut _4: (i32,);
++     scope 1 (inlined <Box<dyn Fn(i32)> as Fn<(i32,)>>::call) {
++         debug self => _3;
++         debug args => _4;
++         let mut _5: &dyn std::ops::Fn(i32);
++         let mut _6: std::boxed::Box<dyn std::ops::Fn(i32)>;
++         let mut _7: *const dyn std::ops::Fn(i32);
++     }
   
       bb0: {
           StorageLive(_2);
@@ -14,19 +21,30 @@
           _3 = &_1;
           StorageLive(_4);
           _4 = (const 1_i32,);
-          _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
+-         _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
++         StorageLive(_5);
++         _6 = deref_copy (*_3);
++         _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));
++         _5 = &(*_7);
++         _2 = <dyn Fn(i32) as Fn<(i32,)>>::call(move _5, move _4) -> [return: bb2, unwind unreachable];
       }
   
       bb1: {
++         return;
++     }
++ 
++     bb2: {
++         StorageDead(_5);
           StorageDead(_4);
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
-          drop(_1) -> [return: bb2, unwind unreachable];
-      }
-  
-      bb2: {
-          return;
+-         drop(_1) -> [return: bb2, unwind unreachable];
+-     }
+- 
+-     bb2: {
+-         return;
++         drop(_1) -> [return: bb1, unwind unreachable];
       }
   }