The problem with that is that making a function safe means that you guarantee that these invariants are enforced. If you tag a function as safe erroneously you basically throw Rust's safety out of the window.
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?
> If you tag a function as safe erroneously you basically throw Rust's safety out of the window.
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.
If an interface can break safe Rust (without that being an implementation bug) then it should not be marked as safe. Breaking safety isn't about the compiler being pedantic, it can break your real world program.
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".
I don't understand what you mean. You can always use "unsafe" anywhere in your code, if autoCXX marked all interface code as unsafe you'd never be stuck because of it, it would just mean that you'd had to check the safety of the C++ function yourself and, if you deem that your usage is kosher, add an unsafe block around your call.
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.
Actually, many C and C++ functions that take no variables at all are unsafe to call because they update shared global state (and tacitly assume that the user of the library will not do this more than once). Initialization functions for example.
Indeed. In my experience it's also fairly common for C and C++ functions to be non-thread safe and have the implicit restriction that they should always be called from the same thread. OpenGL being a good example of that.
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.
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++:
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?