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 new file mode 100644 index 0000000000000..04ace332f1005 --- /dev/null +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.rs @@ -0,0 +1,31 @@ +// 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>(()); + Ok::<_, empty::EmptyForeignEnum>(()); + Ok::<_, empty::VisiblyUninhabitedForeignStruct>(()); + Ok::<_, empty::SecretlyUninhabitedForeignStruct>(()); //~ warn: unused `Result` that must be used + Ok::<_, !>(()); + + Ok::<_, !>(Important); //~ warn: unused `Important` that must be used + + very_important(); //~ warn: unused return value of `very_important` 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..dc7eca91e47c2 --- /dev/null +++ b/tests/ui/lint/unused/must-use-uninhabited-result-e.stderr @@ -0,0 +1,42 @@ +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 +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::<_, empty::SecretlyUninhabitedForeignStruct>(()); + | +++++++ + +warning: unused `Important` that must be used + --> $DIR/must-use-uninhabited-result-e.rs:22:5 + | +LL | Ok::<_, !>(Important); + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = Ok::<_, !>(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: 3 warnings emitted +