about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs18
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs34
-rw-r--r--src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs27
-rw-r--r--src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr14
-rw-r--r--src/test/ui/lang-items/issue-83471.rs23
-rw-r--r--src/test/ui/lang-items/issue-83471.stderr51
6 files changed, 161 insertions, 6 deletions
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 1cc06b8c2e5..e007d971bb0 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -246,12 +246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if borrow {
                     // Check for &self vs &mut self in the method signature. Since this is either
                     // the Fn or FnMut trait, it should be one of those.
-                    let (region, mutbl) =
-                        if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() {
-                            (r, mutbl)
-                        } else {
-                            span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
-                        };
+                    let (region, mutbl) = if let ty::Ref(r, _, mutbl) =
+                        method.sig.inputs()[0].kind()
+                    {
+                        (r, mutbl)
+                    } else {
+                        // The `fn`/`fn_mut` lang item is ill-formed, which should have
+                        // caused an error elsewhere.
+                        self.tcx
+                            .sess
+                            .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?");
+                        return None;
+                    };
 
                     let mutbl = match mutbl {
                         hir::Mutability::Not => AutoBorrowMutability::Not,
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 01ec801228e..d9f9d9dafff 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -200,6 +200,40 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     };
     check_object_unsafe_self_trait_by_name(tcx, &trait_item);
     check_associated_item(tcx, trait_item.hir_id(), span, method_sig);
+
+    let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
+    let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+    if [tcx.lang_items().fn_trait(), tcx.lang_items().fn_mut_trait()]
+        .contains(&Some(encl_trait.def_id.to_def_id()))
+        && trait_item.ident.name.to_ident_string() == "call"
+    {
+        // We are looking at the `call` function of the `fn` or `fn_mut` lang item.
+        // Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
+        if let Some(method_sig @ hir::FnSig { decl, .. }) = method_sig {
+            if let &[self_ty, _] = &decl.inputs {
+                if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+                    tcx.sess.struct_span_err(
+                        self_ty.span,
+                        "first argument of `call` in `fn`/`fn_mut` lang item must be a reference",
+                    ).emit();
+                }
+            } else {
+                tcx.sess
+                    .struct_span_err(
+                        method_sig.span,
+                        "`call` function in `fn`/`fn_mut` lang item takes exactly two arguments",
+                    )
+                    .emit();
+            }
+        } else {
+            tcx.sess
+                .struct_span_err(
+                    trait_item.span,
+                    "`call` trait item in `fn`/`fn_mut` lang item must be a function",
+                )
+                .emit();
+        }
+    }
 }
 
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs
new file mode 100644
index 00000000000..90dc972d8a8
--- /dev/null
+++ b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs
@@ -0,0 +1,27 @@
+// Make sure that an error is reported if the `call` function of the
+// `fn`/`fn_mut` lang item is grossly ill-formed.
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "fn"]
+trait MyFn<T> {
+    const call: i32 = 42;
+    //~^ ERROR: `call` trait item in `fn`/`fn_mut` lang item must be a function
+}
+
+#[lang = "fn_mut"]
+trait MyFnMut<T> {
+    fn call(i: i32, j: i32) -> i32 { i + j }
+    //~^ ERROR: first argument of `call` in `fn`/`fn_mut` lang item must be a reference
+}
+
+fn main() {
+    let a = || 42;
+    a();
+
+    let mut i = 0;
+    let mut b = || { i += 1; };
+    b();
+}
diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr
new file mode 100644
index 00000000000..fea8e52b891
--- /dev/null
+++ b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr
@@ -0,0 +1,14 @@
+error: `call` trait item in `fn`/`fn_mut` lang item must be a function
+  --> $DIR/fn-fn_mut-call-ill-formed.rs:10:5
+   |
+LL |     const call: i32 = 42;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: first argument of `call` in `fn`/`fn_mut` lang item must be a reference
+  --> $DIR/fn-fn_mut-call-ill-formed.rs:16:16
+   |
+LL |     fn call(i: i32, j: i32) -> i32 { i + j }
+   |                ^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lang-items/issue-83471.rs b/src/test/ui/lang-items/issue-83471.rs
new file mode 100644
index 00000000000..b32aa034151
--- /dev/null
+++ b/src/test/ui/lang-items/issue-83471.rs
@@ -0,0 +1,23 @@
+// Regression test for the ICE reported in issue #83471.
+
+#![crate_type="lib"]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "sized"]
+//~^ ERROR: language items are subject to change [E0658]
+trait Sized {}
+
+#[lang = "fn"]
+//~^ ERROR: language items are subject to change [E0658]
+//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument
+trait Fn {
+    fn call(export_name);
+    //~^ ERROR: expected type
+    //~| WARNING: anonymous parameters are deprecated
+    //~| WARNING: this is accepted in the current edition
+}
+fn call_through_fn_trait() {
+    a()
+    //~^ ERROR: cannot find function
+}
diff --git a/src/test/ui/lang-items/issue-83471.stderr b/src/test/ui/lang-items/issue-83471.stderr
new file mode 100644
index 00000000000..c6130bb3370
--- /dev/null
+++ b/src/test/ui/lang-items/issue-83471.stderr
@@ -0,0 +1,51 @@
+error[E0573]: expected type, found built-in attribute `export_name`
+  --> $DIR/issue-83471.rs:15:13
+   |
+LL |     fn call(export_name);
+   |             ^^^^^^^^^^^ not a type
+
+error[E0425]: cannot find function `a` in this scope
+  --> $DIR/issue-83471.rs:21:5
+   |
+LL |     a()
+   |     ^ not found in this scope
+
+error[E0658]: language items are subject to change
+  --> $DIR/issue-83471.rs:7:1
+   |
+LL | #[lang = "sized"]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+error[E0658]: language items are subject to change
+  --> $DIR/issue-83471.rs:11:1
+   |
+LL | #[lang = "fn"]
+   | ^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+warning: anonymous parameters are deprecated and will be removed in the next edition.
+  --> $DIR/issue-83471.rs:15:13
+   |
+LL |     fn call(export_name);
+   |             ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name`
+   |
+   = note: `#[warn(anonymous_parameters)]` on by default
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+
+error[E0718]: `fn` language item must be applied to a trait with 1 generic argument
+  --> $DIR/issue-83471.rs:11:1
+   |
+LL | #[lang = "fn"]
+   | ^^^^^^^^^^^^^^
+...
+LL | trait Fn {
+   |         - this trait has 0 generic arguments
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0425, E0573, E0658, E0718.
+For more information about an error, try `rustc --explain E0425`.