Skip to content

Commit f0b40f5

Browse files
committed
unused_must_use: Don't warn on Result<(), Uninhabited>
This suppresses warnings on things like `Result<(), !>`, which helps simplify code using the common pattern of having an `Error` associated type: code will only have to check the error if there is a possibility of error.
1 parent 2997070 commit f0b40f5

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
291291
is_ty_must_use(cx, pinned_ty, expr, span)
292292
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
293293
}
294+
// Suppress warnings on `Result<(), UninhabitedType>` (e.g. `Result<(), !>`).
295+
ty::Adt(def, args)
296+
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
297+
&& args.type_at(0).is_unit()
298+
&& !args.type_at(1).is_inhabited_from(
299+
cx.tcx,
300+
parent_mod_did,
301+
cx.typing_env(),
302+
) =>
303+
{
304+
Some(MustUsePath::Suppressed)
305+
}
294306
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
295307
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
296308
elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied())
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub enum MyUninhabited {}
2+
3+
#[non_exhaustive]
4+
pub enum MyUninhabitedNonexhaustive {}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@ edition: 2024
2+
//@ aux-crate:dep=must_use_result_unit_uninhabited_extern_crate.rs
3+
4+
#![deny(unused_must_use)]
5+
#![feature(never_type)]
6+
7+
use dep::{MyUninhabited, MyUninhabitedNonexhaustive};
8+
9+
fn f1() -> Result<(), ()> {
10+
Ok(())
11+
}
12+
13+
fn f2() -> Result<(), core::convert::Infallible> {
14+
Ok(())
15+
}
16+
17+
fn f3() -> Result<(), !> {
18+
Ok(())
19+
}
20+
21+
fn f4() -> Result<(), MyUninhabited> {
22+
Ok(())
23+
}
24+
25+
fn f5() -> Result<(), MyUninhabitedNonexhaustive> {
26+
Ok(())
27+
}
28+
29+
trait AssocType {
30+
type Error;
31+
}
32+
33+
struct S1;
34+
impl AssocType for S1 {
35+
type Error = !;
36+
}
37+
38+
struct S2;
39+
impl AssocType for S2 {
40+
type Error = ();
41+
}
42+
43+
fn f6<AT: AssocType>(_: AT) -> Result<(), AT::Error> {
44+
Ok(())
45+
}
46+
47+
fn main() {
48+
f1(); //~ ERROR: unused `Result` that must be used
49+
f2();
50+
f3();
51+
f4();
52+
f5(); //~ ERROR: unused `Result` that must be used
53+
f6(S1);
54+
f6(S2); //~ ERROR: unused `Result` that must be used
55+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: unused `Result` that must be used
2+
--> $DIR/must_use-result-unit-uninhabited.rs:48:5
3+
|
4+
LL | f1();
5+
| ^^^^
6+
|
7+
= note: this `Result` may be an `Err` variant, which should be handled
8+
note: the lint level is defined here
9+
--> $DIR/must_use-result-unit-uninhabited.rs:4:9
10+
|
11+
LL | #![deny(unused_must_use)]
12+
| ^^^^^^^^^^^^^^^
13+
help: use `let _ = ...` to ignore the resulting value
14+
|
15+
LL | let _ = f1();
16+
| +++++++
17+
18+
error: unused `Result` that must be used
19+
--> $DIR/must_use-result-unit-uninhabited.rs:52:5
20+
|
21+
LL | f5();
22+
| ^^^^
23+
|
24+
= note: this `Result` may be an `Err` variant, which should be handled
25+
help: use `let _ = ...` to ignore the resulting value
26+
|
27+
LL | let _ = f5();
28+
| +++++++
29+
30+
error: unused `Result` that must be used
31+
--> $DIR/must_use-result-unit-uninhabited.rs:54:5
32+
|
33+
LL | f6(S2);
34+
| ^^^^^^
35+
|
36+
= note: this `Result` may be an `Err` variant, which should be handled
37+
help: use `let _ = ...` to ignore the resulting value
38+
|
39+
LL | let _ = f6(S2);
40+
| +++++++
41+
42+
error: aborting due to 3 previous errors
43+

0 commit comments

Comments
 (0)