Looks like there are only a few cases where must_use on a generic type parameter would make sense. For example, what fn f() -> Vec<#[must_use] T> would mean?
If your primary concern is the f()?; case, it makes sense to only handle functions that return types that implement Carrier. I think it should be possible to make it work like this:
#[must_use_ok]
fn f() -> Result<T, E> { ... }
Then the compiler will issue a warning to both f(); and f()?;. It doesn’t have to care what the exact structure of the return type is. If f()'s return type does not implement Carrier, adding #[must_use_ok] to it will result in an error. (The must_use_ok name is not great, though.)
There is also the f().unwrap(); case that isn’t backed by a trait. While it’s possible to add special handling for Result and Option here, it’s hard to imagine a way to handle this for any custom type. Imagine a type like this:
enum MyResult<T> {
Ok(T),
Err,
}
struct MyAccessWrapper<T>(T);
impl<T> MyResult<T> {
fn my_unwrap(self) -> MyAccessWrapper<T> {
match self {
MyResult::Ok(v) => MyAccessWrapper(v),
MyResult::Err => panic!("err")
}
}
}
Even if you declare your function to return MyResult<#[must_use] T>, the compiler doesn’t have a way to handle the f().my_unwrap(); case. The name of the unwrap function isn’t unwrap and its return type is not T, so it’s not clear in general that the return value of my_unwrap() must be used in this case.