Unbounded lifetime parameters in vtable method signature, if method return type has a lifetime bounded by Self
This bug happens when the return type has a lifetime bounded by &self. Because in the vtable, &self is casted into a lifetime-less raw pointer ffi::c_void, therefore the vtable method's return type becomes unbounded.
Minimum Reproducible Example
#[thin_trait_object]
trait Foo: 'static {
fn as_slice(&self) -> &[u32];
}
We get
error[E0106]: missing lifetime specifier
--> src\render.rs:9:27
|
9 | fn as_slice(&self) -> &[u64];
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
7 ~ for<'a> #[thin_trait_object]
8 | trait Foo {
9 ~ fn as_slice(&self) -> &'a [u64];
|
help: consider using the `'static` lifetime
|
9 | fn as_slice(&self) -> &'static [u64];
The expanded macro
#[repr(C)]
struct FooVtable {
pub as_slice: unsafe fn(*mut ::core::ffi::c_void) -> &[u64], // <---- This is problematic
pub drop: unsafe fn(*mut ::core::ffi::c_void),
}
Some thoughts
An immediate solution is to replace the vtable method's return type with raw pointers. However, the problem is that this only works with plain references, and other lifetime-bounded types will still be affected (Iterators, some smart pointers, etc). Fully covering these cases seems too much.
I don't have much experience with unsafe hacks and didn't see a particularly good way to fix this. However, this issue is not urgent since copy-pasting cargo expand and manual-fixing always works.