Given that C++ has no explicit concept of safety it seems like it would be hard to do that automatically as soon as pointers or references are involved.
As a quick example: if you have the following signature in C++:
int *foo(int &a);
How you automatically generate safe FFI for it?As a human doing the same task I'd have to ask myself at the very least:
- Can the return value be NULL?
- Can the return value alias a?
- What's the lifetime of the returned value and who owns it?
You really don't. Rust checks are applied to the code written in Rust. If a developer intentionally marked a dependency as safe then you get exactly what you've asked for.
Sometimes it's unquestionably better to have a working system than not having one just because a pedantic compiler complains about stuff that you can't do nothing about.
Yes this may mean you sometimes can't create a safe interface to a particular foreign function. However all this means is that calling the function requires an explicit unsafe block and extra care. But that 'unsafe' marker is valuable! It's something that screams "here be dragons".
If you erroneously tag unsafe interfaces as safe then you basically throw all of Rust's safety out of the window. You can end up with multiple mutable borrows, or borrows with a bogus lifetime or whatever.
Raw bindings to OpenGL in Rust is actually a good example of FFI that wouldn't be safe to call for about half a trillion reasons. There are so many implicit constraints in there that even manually designing a safe Rust interface is a rather complicated endeavor.
If this is not the case, then this whole library thing is _unsound_. We really need an "intentially-broken" tag in crates.io to identify crates that lie about their soundness intentionally.