about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_ast_lowering/item.rs14
-rw-r--r--src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs11
-rw-r--r--src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr19
3 files changed, 43 insertions, 1 deletions
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 5186e62fbf9..699f5c9778a 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -5,7 +5,7 @@ use crate::Arena;
 use rustc_ast::ast::*;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -75,6 +75,18 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         }
     }
 
+    fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
+        match fk {
+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {
+                self.visit_fn_header(&sig.header);
+                visit::walk_fn_decl(self, &sig.decl);
+                // Don't visit the foreign function body even if it has one, since lowering the
+                // body would have no meaning and will have already been caught as a parse error.
+            }
+            _ => visit::walk_fn(self, fk, sp),
+        }
+    }
+
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
         self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
             AssocCtxt::Trait => {
diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs
new file mode 100644
index 00000000000..a84065e0218
--- /dev/null
+++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs
@@ -0,0 +1,11 @@
+// Previously this ICE'd because `fn g()` would be lowered, but the block associated with `fn f()`
+// wasn't.
+
+// compile-flags: --crate-type=lib
+
+extern "C" {
+    fn f() {
+    //~^ incorrect function inside `extern` block
+        fn g() {}
+    }
+}
diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr
new file mode 100644
index 00000000000..d4a9ca3e7c6
--- /dev/null
+++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr
@@ -0,0 +1,19 @@
+error: incorrect function inside `extern` block
+  --> $DIR/issue-74120-lowering-of-ffi-block-bodies.rs:7:8
+   |
+LL |   extern "C" {
+   |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |       fn f() {
+   |  ________^___-
+   | |        |
+   | |        cannot have a body
+LL | |
+LL | |         fn g() {}
+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
+