Repository: rust
Issue: edition idioms lints: `unused_extern_crate` false positives
Labels: A-lints,T-compiler,C-bug,A-edition-2018

### STR

1. Crates that provide lang items

``` console
$ cargo new --bin foo && cd $_

$ cargo add panic-abort # or any other crate only provides a `panic_handler` function

$ cat >src/main.rs <<'EOF'
#![no_main]
#![no_std]

extern crate panic_abort;
EOF

$ # ignore linking; it's not important for this example
$ # also set panic to abort to simplify things
$ mkdir .cargo
$ cat >.cargo/config <<'EOF'
[build]
rustflags = ["-C", "panic=abort", "-C", "linker=true"]
EOF

$ cargo build && echo OK
OK

$ cargo rustc -- -D rust_2018_idioms
   Compiling foo v0.1.0 (file:///home/japaric/tmp/foo)
error: unused extern crate
 --> src/main.rs:4:1
  |
4 | extern crate panic_abort;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
  |
  = note: `-D unused-extern-crates` implied by `-D rust-2018-idioms`

error: aborting due to previous error
```

Removing the `extern crate` as per the suggestion breaks *compilation*:

``` console
$ cat src/main.rs
```

``` rust
#![no_main]
#![no_std]

// extern crate panic_abort;
```

``` console
$ cargo build
   Compiling foo v0.1.0 (file:///home/japaric/tmp/foo)
error: `#[panic_handler]` function required, but not found

error: aborting due to previous error
```

2. Crates that inject symbols dependencies

```
$ git clone https://github.com/rust-embedded/embedonomicon --branch edition-lint-false-positive-do-not-delete

$ cd embedonomicon/ci/main/app

$ cat src/main.rs
```

``` rust
#![feature(panic_handler)]
#![no_std]
#![no_main]

extern crate rt;

use core::panic::PanicInfo;

#[no_mangle]
pub fn main() -> ! {
    let _x = 42;

    loop {}
}

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
    loop {}
}
```

``` console
$ rustup target add thumbv7m-none-eabi
$ cargo build && echo OK
OK

$ cargo rustc -- -D rust_2018_idioms
cargo rustc -- -D rust_2018_idioms
   Compiling app v0.1.0 (file:///home/japaric/tmp/embedonomicon/ci/main/app)
error: unused extern crate
 --> src/main.rs:4:1
  |
4 | extern crate rt;
  | ^^^^^^^^^^^^^^^^ help: remove it
  |
  = note: `-D unused-extern-crates` implied by `-D rust-2018-idioms`

error: aborting due to previous error
```

Removing the `extern crate` as suggested breaks *linking*.

``` console
$ sed -i '/extern crate/d' src/main.rs
$ cargo build
error: linking with `rust-lld` failed: exit code: 1
  |
  = note: "rust-lld" "-flavor" "gnu" (..)
  = note: rust-lld: error: malformed / incomplete vector table
```

The error above is a custom assertion that checks that the binary has the right memory layout. Removing `extern crate rt` produces an invalid (empty) binary.

### Metadata

``` console
$ rustc -V
rustc 1.30.0-nightly (1c2e17f4e 2018-09-04)
```

---

(2) seems unfixable, or at least very hard to properly fix, to me since it requires knowing the dependencies between symbols and symbol information is only complete / exact after optimization, plus linker scripts can make some symbols required. A good enough fix could be to not warn about crates that expose public, reachable `#[no_mangle]` / `#[export_name]` symbols. In any case, I expect that in practice not many people will encounter this warning.

(1) should be fixable and should be fixed. The compiler should be able to determine if a crate contains lang items. This scenario I expect to be much more common since some of us, embedded devs, like to pack `panic_handler`s in crates as that makes it easy to switch between them.