diff options
| author | bors <bors@rust-lang.org> | 2023-11-19 12:23:59 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-19 12:23:59 +0000 |
| commit | 097261f241d0295a84a1fc754639e58202ea7e8e (patch) | |
| tree | ada2eaff0c5485ef44c05df190933c94a37625b6 | |
| parent | 10a98e8bff0b1335e7f0f1ea0453ee0765ae96fe (diff) | |
| parent | c5ed7b0ead27a9b666c2c4fc14160fba972df793 (diff) | |
Auto merge of #118054 - max-niederman:pinned-must-use, r=Nilstrieb
Lint pinned `#[must_use]` pointers (in particular, `Box<T>` where `T` is `#[must_use]`) in `unused_must_use`.
Fixes: #111458
This is motivated by a common async/await pattern:
```rs
fn foo() -> Pin<Box<dyn Future<Output = i32>>> {
Box::pin(async { 42 })
}
// call `foo`, but forget to await the result
foo();
```
Unlike with `async fn` or return position `impl Future`, this does not currently warn the user that the `Future` is unused.
To fix this, I've extended the `unused_must_use` lint to catch `Pin<P>`, where `P` must be used. In particular, this applies to `Pin<Box<T>>`, where `T` must be used. I'm not sure if there are other pointers where this applies, but I can't think of any situation the user wouldn't want to be warned.
| -rw-r--r-- | compiler/rustc_lint/src/unused.rs | 18 | ||||
| -rw-r--r-- | tests/ui/lint/unused/must_use-pin.rs | 45 | ||||
| -rw-r--r-- | tests/ui/lint/unused/must_use-pin.stderr | 20 |
3 files changed, 83 insertions, 0 deletions
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 355855b8e2b..0ae91ac28a7 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -251,6 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { /// The root of the normal must_use lint with an optional message. Def(Span, DefId, Option<Symbol>), Boxed(Box<Self>), + Pinned(Box<Self>), Opaque(Box<Self>), TraitObject(Box<Self>), TupleElement(Vec<(usize, Self)>), @@ -284,6 +285,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { is_ty_must_use(cx, boxed_ty, expr, span) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } + ty::Adt(def, args) if cx.tcx.lang_items().pin_type() == Some(def.did()) => { + let pinned_ty = args.type_at(0); + is_ty_must_use(cx, pinned_ty, expr, span) + .map(|inner| MustUsePath::Pinned(Box::new(inner))) + } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { elaborate( @@ -425,6 +431,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { expr_is_from_block, ); } + MustUsePath::Pinned(path) => { + let descr_pre = &format!("{descr_pre}pinned "); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); + } MustUsePath::Opaque(path) => { let descr_pre = &format!("{descr_pre}implementer{plural_suffix} of "); emit_must_use_untranslated( diff --git a/tests/ui/lint/unused/must_use-pin.rs b/tests/ui/lint/unused/must_use-pin.rs new file mode 100644 index 00000000000..b08515428b1 --- /dev/null +++ b/tests/ui/lint/unused/must_use-pin.rs @@ -0,0 +1,45 @@ +#![deny(unused_must_use)] + +use std::{ops::Deref, pin::Pin}; + +#[must_use] +struct MustUse; + +#[must_use] +struct MustUsePtr<'a, T>(&'a T); + +impl<'a, T> Deref for MustUsePtr<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +fn pin_ref() -> Pin<&'static ()> { + Pin::new(&()) +} + +fn pin_ref_mut() -> Pin<&'static mut ()> { + Pin::new(unimplemented!()) +} + +fn pin_must_use_ptr() -> Pin<MustUsePtr<'static, ()>> { + Pin::new(MustUsePtr(&())) +} + +fn pin_box() -> Pin<Box<()>> { + Box::pin(()) +} + +fn pin_box_must_use() -> Pin<Box<MustUse>> { + Box::pin(MustUse) +} + +fn main() { + pin_ref(); + pin_ref_mut(); + pin_must_use_ptr(); //~ ERROR unused pinned `MustUsePtr` that must be used + pin_box(); + pin_box_must_use(); //~ ERROR unused pinned boxed `MustUse` that must be used +} diff --git a/tests/ui/lint/unused/must_use-pin.stderr b/tests/ui/lint/unused/must_use-pin.stderr new file mode 100644 index 00000000000..c04f8fef487 --- /dev/null +++ b/tests/ui/lint/unused/must_use-pin.stderr @@ -0,0 +1,20 @@ +error: unused pinned `MustUsePtr` that must be used + --> $DIR/must_use-pin.rs:42:5 + | +LL | pin_must_use_ptr(); + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/must_use-pin.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused pinned boxed `MustUse` that must be used + --> $DIR/must_use-pin.rs:44:5 + | +LL | pin_box_must_use(); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + |
