Rollup merge of #74204 - ayazhafiz:i/74120, r=eddyb

Don't visit foreign function bodies when lowering ast to hir

Previously the existence of bodies inside a foreign function block would
cause a panic in the hir `NodeCollector` during its collection of crate
bodies to compute a crate hash:

e59b08e62e/src/librustc_middle/hir/map/collector.rs (L154-L158)

The collector walks the hir tree and creates a map of hir nodes, then
attaching bodies in the crate to their owner in the map. For a code like

```rust
extern "C" {
    fn f() {
        fn g() {}
    }
}
```

The crate bodies include the body of the function `g`. But foreign
functions cannot have bodies, and while the parser AST permits a foreign
function to have a body, the hir doesn't. This means that the body of
`f` is not present in the hir, and so neither is `g`. So when the
`NodeCollector` finishes the walking the hir, it has no record of `g`,
cannot find an owner for the body of `g` it sees in the crate bodies,
and blows up.

Why do the crate bodies include the body of `g`? The AST walker has a
need a for walking function bodies, and FFIs share the same AST node as
functions in other contexts.

There are at least two options to fix this:

- Don't unwrap the map entry for an hir node in the `NodeCollector`
- Modifier the ast->hir lowering visitor to ignore foreign function
  blocks

I don't think the first is preferrable, since we want to know when we
can't find a body for an hir node that we thought had one (dropping this
information may lead to an invalid hash). So this commit implements the
second option.

Closes #74120
This commit is contained in:
Tyler Mandry 2020-08-16 14:59:20 -07:00 committed by GitHub
commit 8eba138d5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 1 deletions

View file

@ -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() {}
}
}

View file

@ -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