Description
General issue
Currently, #[must_use]
on a trait Foo
does not extend to types that implement Foo
, it only works on impl Foo
return types, and Box<dyn Foo>
as a special case:
#[must_use]
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn build_foo() -> impl Foo { Bar }
fn build_box() -> Box<dyn Foo> { Box::new(Bar) }
fn build_bar() -> Bar { Bar }
fn main() {
build_foo(); // warning: unused implementer of `Foo` that must be used
build_box(); // warning: unused boxed `Foo` trait object that must be used
build_bar(); // no warning!
}
This does not make much sense, presumably if a trait must always be used all types that implement that trait must also be used.
Application to Future
I came across this when dealing with futures. The Future trait has a #[must_use]
annotation, with the useful reminder to .await
or poll them:
rust/library/core/src/future/future.rs
Lines 28 to 37 in b8967b0
I was specifically using specifically BoxFuture
, a type alias for Pin<Box<dyn Future>>
. This type implements Future
, but there is no warning message when you forget to use it. This was also the original justification in #67387, where a very different solution is proposed (extending must_use
to Pin
and other wrapper types).
Another effect of this missing warning is that any struct that implements Future
has to repeat the same must_use
annotation. Some examples:
futures::future::Ready
tokio::time::Sleep
async_std
doesn't expose any public types that implementFuture
, instead they almost always use animpl Future
return type. There is still the internalWriteFmtFuture
.
If must_use
on traits infected any type that implemented it, these duplicate annotations could be removed and there would be no risk of forgetting them for any future types.