Repository: rust
Issue: improper_ctypes_definitions doesn't lint on non-FFI safe fn type construction
Labels: A-diagnostics,T-compiler

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.

If you cannot produce a minimal reproduction case (something that would work in
isolation), please provide the steps or even link to a repository that causes
the problematic output to occur.
-->

Given the following code: <!-- Please provide a link to play.rust-lang.org -->

```rust
#![deny(improper_ctypes_definitions)]
pub extern "C" fn third(_a: usize, b: usize, c: usize) -> usize {
    println!("arg 2 {} arg 3 {}", b, c);
    c
}


fn main() {
    let f: extern "C" fn(usize, usize, usize)->usize = third;
    let normal_third = f(1,2,3);
    assert_eq!(normal_third, 3, "normal_third");
    
    // we know that third never uses the first argument, so let's just replace it
    // it with a unit! the other two parameters should still be fine, right?
    //
    // (note that this doesn't give an improper_ctypes_definitions warning, because
    // we don't have a *definition*, only an improper extern fn type :( )
    let throw_away_f: extern "C" fn((), usize, usize)->usize =
        unsafe { std::mem::transmute(third as extern "C" fn(_,_,_)->_) };
    let throw_away_third = throw_away_f((),2,3);
    // uh-oh! the zero-sized type was actually *removed* from our systemv calling
    // convention entirely, shifting our registers over and making `c` junk!
    assert_eq!(throw_away_third, 3, "throw_away_third");
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=55030237a20e0b249ad7d977a8f6f75f)
The current output is:

```
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `94536864439520`,
 right: `3`: throw_away_third', src/main.rs:23:5
```

<!-- The following is not always necessary. -->
Ideally the output should look like:

```
error: `extern` fn uses type `()`, which is not FFI-safe
17 |    let throw_away_f: extern "C" fn((), usize, usize)->usize =
  |                                        ^^ not FFI-safe
```

<!--
If the problem is not self-explanatory, please provide a rationale for the
change.
-->
Currently, the improper_ctypes_definitions lint will warn only for declarations of extern functions with non-FFI arguments (such as `pub extern "C" fn throw_away_third(_: (), b: usize, c: usize) -> usize { ... }`), but doesn't warn on just *using* the fn type itself, so it doesn't help in cases where you e.g. transmute a JIT function to an fn type and use it/include it in struct types itself. This kinda makes sense, in that the lint name is improper_ctypes_definitions, but my assumption when writing the code was that there was "that function FFI type safety lint" that would warn if I did something stupid without directly remembering the name.

<!--
If dramatically different output is caused by small changes, consider also
adding them here.

If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions. The output might also be
different depending on the Edition.
-->