The issue is that it’s not currently possible to specify (in a generic way) that a function can only be called from an unsafe context.
This is useful in libraries like libloading and inkwell where you routinely produce function pointers that need to be cast to the correct signature and calling convention (see ExecutionEngine::get_function() and TheDan64/inkwell#36). These functions are innately unsafe to call because there’s no guarantee that they have the correct signature, calling convention, or even still exist (e.g. the JIT could be destroyed or dynamic library unloaded from memory), but the type system doesn’t currently have any mechanism for specifying this constraint.
Would it be useful to propose some sort of UnsafeFn trait for functions which are only callable from unsafe code? Also, is there any way to specify something like calling convention via the type system?
To avoid needing to duplicate all the traits (UnsafeFn, UnsafeAdd, etc) hopefully we can get (strawman syntax) impl unsafe Fn for Foo and where F: unsafe Fn, or something like that.
How would an effects system interact with things like #[repr] and calling convention? Ideally it’d be nice for libloading and inkwell to constrain the calling convention for any function pointers they hand out.
How would that differ from unsafe impl Fn for Foo, which already exists (and is e.g. used to implement traits that are safe to use, but unsafe to implement e.g. Send and Sync)?
unsafe impl Add for Foo would be an error, as Add isn’t an unsafe trait. impl unsafe Add for Foo would make foo1 + foo2 only callable in an unsafe context.
So then technically something like unsafe impl unsafe Add for Foo { /* ...*/ } would be a valid (if redundant) definition?
Or would rustc forbid that combination?
I was picturing that, since Add isn’t an unsafe trait, that particular case would be an error. But yes, something like unsafe impl unsafe FixedSizeArray<i32> for Foo would be valid. (Of course, this is all strawman syntax.)