about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-11-19 16:26:19 +0100
committerGitHub <noreply@github.com>2020-11-19 16:26:19 +0100
commit5a58b5069873564e37acb42dc2f963b726a769e5 (patch)
treeae96f2809e9fc01589001aacc106f7cb7d0f0581
parent7e2032390cf34f3ffa726b7bd890141e2684ba63 (diff)
parente8426a617b87af7b8254e732ca85951cbae0a6b9 (diff)
downloadrust-5a58b5069873564e37acb42dc2f963b726a769e5.tar.gz
rust-5a58b5069873564e37acb42dc2f963b726a769e5.zip
Rollup merge of #78961 - CraftSpider:22565, r=oli-obk
Make bad "rust-call" arguments no longer ICE

The simplest of bad rust-call definitions will no longer cause an ICE. There is a FIXME added for future work, as I wanted to get this easy fix in before trying to either add a hack or mess with the whole obligation system

fixes #22565
-rw-r--r--compiler/rustc_typeck/src/check/check.rs31
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs2
-rw-r--r--src/test/ui/abi/issues/issue-22565-rust-call.rs8
-rw-r--r--src/test/ui/abi/issues/issue-22565-rust-call.stderr8
-rw-r--r--src/test/ui/abi/rustcall-generic.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.rs12
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.stderr12
-rw-r--r--src/test/ui/overloaded-calls-nontuple.rs2
-rw-r--r--src/test/ui/overloaded-calls-nontuple.stderr16
9 files changed, 85 insertions, 15 deletions
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 1220c313932..d5518dfc15a 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -94,6 +94,37 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     fn_maybe_err(tcx, span, fn_sig.abi);
 
+    if fn_sig.abi == Abi::RustCall {
+        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+        let err = || {
+            let item = match tcx.hir().get(fn_id) {
+                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+                Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(header, ..), ..
+                }) => Some(header),
+                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => None,
+                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+            };
+
+            if let Some(header) = item {
+                tcx.sess.span_err(header.span, "A function with the \"rust-call\" ABI must take a single non-self argument that is a tuple")
+            }
+        };
+
+        if fn_sig.inputs().len() != expected_args {
+            err()
+        } else {
+            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+            //   This will probably require wide-scale changes to support a TupleKind obligation
+            //   We can't resolve this without knowing the type of the param
+            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+                err()
+            }
+        }
+    }
+
     if body.generator_kind.is_some() && can_be_generator.is_some() {
         let yield_ty = fcx
             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index b242900a122..1479eadf1b0 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -108,7 +108,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{HirIdMap, Node};
+use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.rs b/src/test/ui/abi/issues/issue-22565-rust-call.rs
new file mode 100644
index 00000000000..055d959b46e
--- /dev/null
+++ b/src/test/ui/abi/issues/issue-22565-rust-call.rs
@@ -0,0 +1,8 @@
+#![feature(unboxed_closures)]
+
+extern "rust-call" fn b(_i: i32) {}
+//~^ ERROR A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+
+fn main () {
+    b(10);
+}
diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.stderr b/src/test/ui/abi/issues/issue-22565-rust-call.stderr
new file mode 100644
index 00000000000..31fb035eb99
--- /dev/null
+++ b/src/test/ui/abi/issues/issue-22565-rust-call.stderr
@@ -0,0 +1,8 @@
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+  --> $DIR/issue-22565-rust-call.rs:3:1
+   |
+LL | extern "rust-call" fn b(_i: i32) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/abi/rustcall-generic.rs b/src/test/ui/abi/rustcall-generic.rs
new file mode 100644
index 00000000000..2fa41a7e35a
--- /dev/null
+++ b/src/test/ui/abi/rustcall-generic.rs
@@ -0,0 +1,9 @@
+// check-pass
+#![feature(unboxed_closures)]
+
+extern "rust-call" fn foo<T>(_: T) {}
+
+fn main() {
+    foo(());
+    foo((1, 2));
+}
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index e89dc4d5a05..31f09cc61f9 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -15,7 +15,7 @@ extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
 //~^ ERROR intrinsic must be in
 extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
-extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
+extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
 extern "ptx-kernel" fn f6() {} //~ ERROR PTX ABIs are experimental and subject to change
 extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental
@@ -30,7 +30,7 @@ trait Tr {
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
     //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
-    extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
+    extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
     extern "ptx-kernel" fn m6(); //~ ERROR PTX ABIs are experimental and subject to change
     extern "x86-interrupt" fn m7(); //~ ERROR x86-interrupt ABI is experimental
@@ -39,7 +39,7 @@ trait Tr {
     extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change
 
     extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
-    extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
+    extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental
     extern "ptx-kernel" fn dm6() {} //~ ERROR PTX ABIs are experimental and subject to change
     extern "x86-interrupt" fn dm7() {} //~ ERROR x86-interrupt ABI is experimental
@@ -57,7 +57,7 @@ impl Tr for S {
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
     //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
-    extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
+    extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
     extern "ptx-kernel" fn m6() {} //~ ERROR PTX ABIs are experimental and subject to change
     extern "x86-interrupt" fn m7() {} //~ ERROR x86-interrupt ABI is experimental
@@ -73,7 +73,7 @@ impl S {
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
     //~^ ERROR intrinsic must be in
     extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
-    extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
+    extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
     extern "ptx-kernel" fn im6() {} //~ ERROR PTX ABIs are experimental and subject to change
     extern "x86-interrupt" fn im7() {} //~ ERROR x86-interrupt ABI is experimental
@@ -86,7 +86,7 @@ impl S {
 type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
 type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
 type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
-type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change
+type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change
 type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental
 type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change
 type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index 50cd8bc68a2..25f0c259d11 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -26,7 +26,7 @@ LL | extern "vectorcall" fn f3() {}
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:18:8
    |
-LL | extern "rust-call" fn f4() {}
+LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
@@ -113,7 +113,7 @@ LL |     extern "vectorcall" fn m3();
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:33:12
    |
-LL |     extern "rust-call" fn m4();
+LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
@@ -183,7 +183,7 @@ LL |     extern "vectorcall" fn dm3() {}
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:42:12
    |
-LL |     extern "rust-call" fn dm4() {}
+LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
@@ -270,7 +270,7 @@ LL |     extern "vectorcall" fn m3() {}
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:60:12
    |
-LL |     extern "rust-call" fn m4() {}
+LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
@@ -357,7 +357,7 @@ LL |     extern "vectorcall" fn im3() {}
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:76:12
    |
-LL |     extern "rust-call" fn im4() {}
+LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
@@ -444,7 +444,7 @@ LL | type A3 = extern "vectorcall" fn();
 error[E0658]: rust-call ABI is subject to change
   --> $DIR/feature-gate-abi.rs:89:18
    |
-LL | type A4 = extern "rust-call" fn();
+LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
diff --git a/src/test/ui/overloaded-calls-nontuple.rs b/src/test/ui/overloaded-calls-nontuple.rs
index 62a7130ddeb..76b114c5592 100644
--- a/src/test/ui/overloaded-calls-nontuple.rs
+++ b/src/test/ui/overloaded-calls-nontuple.rs
@@ -11,11 +11,13 @@ impl FnMut<isize> for S {
     extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
         self.x + self.y + z
     }
+    //~^^^ ERROR A function with the "rust-call" ABI must take a single non-self argument
 }
 
 impl FnOnce<isize> for S {
     type Output = isize;
     extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+    //~^ ERROR A function with the "rust-call" ABI must take a single non-self argument
 }
 
 fn main() {
diff --git a/src/test/ui/overloaded-calls-nontuple.stderr b/src/test/ui/overloaded-calls-nontuple.stderr
index 82c12c4b6e1..bdadb95db29 100644
--- a/src/test/ui/overloaded-calls-nontuple.stderr
+++ b/src/test/ui/overloaded-calls-nontuple.stderr
@@ -1,9 +1,21 @@
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+  --> $DIR/overloaded-calls-nontuple.rs:11:5
+   |
+LL |     extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+  --> $DIR/overloaded-calls-nontuple.rs:19:5
+   |
+LL |     extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
-  --> $DIR/overloaded-calls-nontuple.rs:26:10
+  --> $DIR/overloaded-calls-nontuple.rs:28:10
    |
 LL |     drop(s(3))
    |          ^^^^
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0059`.