about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late.rs13
-rw-r--r--src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs12
-rw-r--r--src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr21
3 files changed, 43 insertions, 3 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 57305023138..1b02511fd7c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -520,9 +520,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         let rib_kind = match fn_kind {
-            // Bail if there's no body.
-            FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp),
-            FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind,
+            // Bail if the function is foreign, and thus cannot validly have
+            // a body, or if there's no body for some other reason.
+            FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
+                // We don't need to deal with patterns in parameters, because
+                // they are not possible for foreign or bodiless functions.
+                self.visit_fn_header(&sig.header);
+                visit::walk_fn_decl(self, &sig.decl);
+                return;
+            }
+            FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
             FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
             FnKind::Closure(..) => ClosureOrAsyncRibKind,
         };
diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs
new file mode 100644
index 00000000000..2ac3ca29355
--- /dev/null
+++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs
@@ -0,0 +1,12 @@
+// Regression test for issue #91370.
+
+extern {
+    //~^ `extern` blocks define existing foreign functions
+    fn f() {
+        //~^ incorrect function inside `extern` block
+        //~| cannot have a body
+        impl Copy for u8 {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
new file mode 100644
index 00000000000..4fb2f8c659c
--- /dev/null
+++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
@@ -0,0 +1,21 @@
+error: incorrect function inside `extern` block
+  --> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8
+   |
+LL |   extern {
+   |   ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |
+LL |       fn f() {
+   |  ________^___-
+   | |        |
+   | |        cannot have a body
+LL | |
+LL | |
+LL | |         impl Copy for u8 {}
+LL | |     }
+   | |_____- help: remove the invalid body: `;`
+   |
+   = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to previous error
+