From d9fd1ced62b413155bbc10b491b298689dde811c Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 18 Oct 2025 19:39:30 +0200 Subject: [PATCH 1/2] add a test for unused results with uninhabited `E` --- .../unused/must-use-uninhabited-result-e.rs | 32 ++++++ .../must-use-uninhabited-result-e.stderr | 103 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 tests/ui/lint/unused/must-use-uninhabited-result-e.rs create mode 100644 tests/ui/lint/unused/must-use-uninhabited-result-e.stderr diff --git a/tests/ui/lint/unused/must-use-uninhabited-result-e.rs b/tests/ui/lint/unused/must-use-uninhabited-result-e.rs new file mode 100644 index 0000000000000..c3cba888b8194 --- /dev/null +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.rs @@ -0,0 +1,32 @@ +// This test checks for uninhabited error type in a result interacts with must +// use lint. Ideally we don't want to lint on `Result` as something that +// must be used, because it's equivalent to `T`. However, we need to make sure +// that if there are other reasons for the lint, we still emit it. +// +// See also: . +// +//@ aux-build:../../../pattern/usefulness/auxiliary/empty.rs +//@ check-pass +#![warn(unused)] +#![feature(never_type)] + +extern crate empty; + +fn main() { + Ok::<_, std::convert::Infallible>(()); //~ warn: unused `Result` that must be used + Ok::<_, empty::EmptyForeignEnum>(()); //~ warn: unused `Result` that must be used + Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); //~ warn: unused `Result` that must be used + Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); //~ warn: unused `Result` that must be used + Ok::<_, !>(()); //~ warn: unused `Result` that must be used + + Ok::<_, !>(Important); //~ warn: unused `Result` that must be used + + very_important(); //~ warn: unused return value of `very_important` that must be used + //~| warn: unused `Result` that must be used +} + +#[must_use] +struct Important; + +#[must_use] +fn very_important() -> Result<(), !> { Ok(()) } diff --git a/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr b/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr new file mode 100644 index 0000000000000..93dab3379bafb --- /dev/null +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr @@ -0,0 +1,103 @@ +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:16:5 + | +LL | Ok::<_, std::convert::Infallible>(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +note: the lint level is defined here + --> $DIR/must-use-uninhabited-result-e.rs:10:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_must_use)]` implied by `#[warn(unused)]` +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, std::convert::Infallible>(()); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:17:5 + | +LL | Ok::<_, empty::EmptyForeignEnum>(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, empty::EmptyForeignEnum>(()); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:18:5 + | +LL | Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:19:5 + | +LL | Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:20:5 + | +LL | Ok::<_, !>(()); + | ^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, !>(()); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:22:5 + | +LL | Ok::<_, !>(Important); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, !>(Important); + | +++++++ + +warning: unused `Result` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:24:5 + | +LL | very_important(); + | ^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = very_important(); + | +++++++ + +warning: unused return value of `very_important` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:24:5 + | +LL | very_important(); + | ^^^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = very_important(); + | +++++++ + +warning: 8 warnings emitted + From e33d28afc9c841fe83569a80137ae511d7a6c85c Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 18 Oct 2025 19:26:01 +0200 Subject: [PATCH 2/2] allow unused results with an uninhabited error type --- compiler/rustc_lint/src/unused.rs | 13 ++++ .../unused/must-use-uninhabited-result-e.rs | 11 ++- .../must-use-uninhabited-result-e.stderr | 71 ++----------------- 3 files changed, 23 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1594a0361a62c..dbc040ea6cb45 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -293,6 +293,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { is_ty_must_use(cx, pinned_ty, expr, span) .map(|inner| MustUsePath::Pinned(Box::new(inner))) } + ty::Adt(def, args) + // Do not warn against `Result` (or in general when `E` is uninhabitted) + // being unused, unless `T` must be used. + if cx.tcx.is_diagnostic_item(sym::Result, def.did()) + && !args.type_at(1).is_inhabited_from( + cx.tcx, + cx.tcx.parent_module(expr.hir_id).to_def_id(), + cx.typing_env(), + ) => + { + is_ty_must_use(cx, args.type_at(0), expr, span) + } + ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => { elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied()) diff --git a/tests/ui/lint/unused/must-use-uninhabited-result-e.rs b/tests/ui/lint/unused/must-use-uninhabited-result-e.rs index c3cba888b8194..04ace332f1005 100644 --- a/tests/ui/lint/unused/must-use-uninhabited-result-e.rs +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.rs @@ -13,16 +13,15 @@ extern crate empty; fn main() { - Ok::<_, std::convert::Infallible>(()); //~ warn: unused `Result` that must be used - Ok::<_, empty::EmptyForeignEnum>(()); //~ warn: unused `Result` that must be used - Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); //~ warn: unused `Result` that must be used + Ok::<_, std::convert::Infallible>(()); + Ok::<_, empty::EmptyForeignEnum>(()); + Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); //~ warn: unused `Result` that must be used - Ok::<_, !>(()); //~ warn: unused `Result` that must be used + Ok::<_, !>(()); - Ok::<_, !>(Important); //~ warn: unused `Result` that must be used + Ok::<_, !>(Important); //~ warn: unused `Important` that must be used very_important(); //~ warn: unused return value of `very_important` that must be used - //~| warn: unused `Result` that must be used } #[must_use] diff --git a/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr b/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr index 93dab3379bafb..dc7eca91e47c2 100644 --- a/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr @@ -1,8 +1,8 @@ warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:16:5 + --> $DIR/must-use-uninhabited-result-e.rs:19:5 | -LL | Ok::<_, std::convert::Infallible>(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this `Result` may be an `Err` variant, which should be handled note: the lint level is defined here @@ -13,81 +13,20 @@ LL | #![warn(unused)] = note: `#[warn(unused_must_use)]` implied by `#[warn(unused)]` help: use `let _ = ...` to ignore the resulting value | -LL | let _ = Ok::<_, std::convert::Infallible>(()); - | +++++++ - -warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:17:5 - | -LL | Ok::<_, empty::EmptyForeignEnum>(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = Ok::<_, empty::EmptyForeignEnum>(()); - | +++++++ - -warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:18:5 - | -LL | Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); - | +++++++ - -warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:19:5 - | -LL | Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value - | LL | let _ = Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); | +++++++ -warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:20:5 - | -LL | Ok::<_, !>(()); - | ^^^^^^^^^^^^^^ - | - = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = Ok::<_, !>(()); - | +++++++ - -warning: unused `Result` that must be used +warning: unused `Important` that must be used --> $DIR/must-use-uninhabited-result-e.rs:22:5 | LL | Ok::<_, !>(Important); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: this `Result` may be an `Err` variant, which should be handled help: use `let _ = ...` to ignore the resulting value | LL | let _ = Ok::<_, !>(Important); | +++++++ -warning: unused `Result` that must be used - --> $DIR/must-use-uninhabited-result-e.rs:24:5 - | -LL | very_important(); - | ^^^^^^^^^^^^^^^^ - | - = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = very_important(); - | +++++++ - warning: unused return value of `very_important` that must be used --> $DIR/must-use-uninhabited-result-e.rs:24:5 | @@ -99,5 +38,5 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = very_important(); | +++++++ -warning: 8 warnings emitted +warning: 3 warnings emitted