Skip to content

Commit 061f854

Browse files
authored
Rollup merge of #147382 - joshtriplett:unused-must-use-ignore-result-unit-uninhabited, r=fmease
unused_must_use: Don't warn on `Result<(), Uninhabited>` or `ControlFlow<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. This will, for instance, help with future refactorings of `write!` in the standard library. As this is a user-visible change to lint behavior, it'll require a lang FCP. --- My proposal, here, is that we handle this simple case to make common patterns more usable. This does not rule out the possibility of adding more cases in the future, including general trait-based cases. However, I don't think we should make this common case wait on the more general cases. In particular, this solution does not close any doors on replacing this special case with a general case. This would unblock some planned work in the standard library to make `write!` more usable for infallible cases (e.g. writing into a `Vec` or `String`).
2 parents 2a4818d + 7aa7ecc commit 061f854

4 files changed

Lines changed: 206 additions & 7 deletions

File tree

‎compiler/rustc_lint/src/unused.rs‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
273273
expr:&hir::Expr<'_>,
274274
span:Span,
275275
) -> Option<MustUsePath>{
276-
if ty.is_unit()
277-
|| !ty.is_inhabited_from(
278-
cx.tcx,
279-
cx.tcx.parent_module(expr.hir_id).to_def_id(),
280-
cx.typing_env(),
281-
)
282-
{
276+
if ty.is_unit(){
277+
returnSome(MustUsePath::Suppressed);
278+
}
279+
let parent_mod_did = cx.tcx.parent_module(expr.hir_id).to_def_id();
280+
let is_uninhabited =
281+
|t:Ty<'tcx>| !t.is_inhabited_from(cx.tcx, parent_mod_did, cx.typing_env());
282+
ifis_uninhabited(ty){
283283
returnSome(MustUsePath::Suppressed);
284284
}
285285

@@ -293,6 +293,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
293293
is_ty_must_use(cx, pinned_ty, expr, span)
294294
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
295295
}
296+
// Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`).
297+
ty::Adt(def, args)
298+
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
299+
&& args.type_at(0).is_unit()
300+
&& is_uninhabited(args.type_at(1)) =>
301+
{
302+
Some(MustUsePath::Suppressed)
303+
}
304+
// Suppress warnings on `ControlFlow<Uninhabited, ()>` (e.g. `ControlFlow<!, ()>`).
305+
ty::Adt(def, args)
306+
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
307+
&& args.type_at(1).is_unit()
308+
&& is_uninhabited(args.type_at(0)) =>
309+
{
310+
Some(MustUsePath::Suppressed)
311+
}
296312
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
297313
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy{def_id: def, .. }) => {
298314
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+
pubenumMyUninhabited{}
2+
3+
#[non_exhaustive]
4+
pubenumMyUninhabitedNonexhaustive{}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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 core::ops::{ControlFlow,ControlFlow::Continue};
8+
use dep::{MyUninhabited,MyUninhabitedNonexhaustive};
9+
10+
fnresult_unit_unit() -> Result<(),()>{
11+
Ok(())
12+
}
13+
14+
fnresult_unit_infallible() -> Result<(), core::convert::Infallible>{
15+
Ok(())
16+
}
17+
18+
fnresult_unit_never() -> Result<(), !>{
19+
Ok(())
20+
}
21+
22+
fnresult_unit_myuninhabited() -> Result<(),MyUninhabited>{
23+
Ok(())
24+
}
25+
26+
fnresult_unit_myuninhabited_nonexhaustive() -> Result<(),MyUninhabitedNonexhaustive>{
27+
Ok(())
28+
}
29+
30+
traitAssocType{
31+
typeError;
32+
}
33+
34+
structS1;
35+
implAssocTypeforS1{
36+
typeError = !;
37+
}
38+
39+
structS2;
40+
implAssocTypeforS2{
41+
typeError = ();
42+
}
43+
44+
fnresult_unit_assoctype<AT:AssocType>(_:AT) -> Result<(),AT::Error>{
45+
Ok(())
46+
}
47+
48+
traitUsesAssocType{
49+
typeError;
50+
fnmethod_use_assoc_type(&self) -> Result<(),Self::Error>;
51+
}
52+
53+
implUsesAssocTypeforS1{
54+
typeError = !;
55+
fnmethod_use_assoc_type(&self) -> Result<(),Self::Error>{
56+
Ok(())
57+
}
58+
}
59+
60+
implUsesAssocTypeforS2{
61+
typeError = ();
62+
fnmethod_use_assoc_type(&self) -> Result<(),Self::Error>{
63+
Err(())
64+
}
65+
}
66+
67+
fncontrolflow_unit() -> ControlFlow<()>{
68+
Continue(())
69+
}
70+
71+
fncontrolflow_infallible_unit() -> ControlFlow<core::convert::Infallible,()>{
72+
Continue(())
73+
}
74+
75+
fncontrolflow_never() -> ControlFlow<!>{
76+
Continue(())
77+
}
78+
79+
fnmain(){
80+
result_unit_unit();//~ ERROR: unused `Result` that must be used
81+
result_unit_infallible();
82+
result_unit_never();
83+
result_unit_myuninhabited();
84+
result_unit_myuninhabited_nonexhaustive();//~ ERROR: unused `Result` that must be used
85+
result_unit_assoctype(S1);
86+
result_unit_assoctype(S2);//~ ERROR: unused `Result` that must be used
87+
S1.method_use_assoc_type();
88+
S2.method_use_assoc_type();//~ ERROR: unused `Result` that must be used
89+
90+
controlflow_unit();//~ ERROR: unused `ControlFlow` that must be used
91+
controlflow_infallible_unit();
92+
controlflow_never();
93+
}
94+
95+
traitAssocTypeBeforeMonomorphisation{
96+
typeError;
97+
fngenerate(&self) -> Result<(),Self::Error>;
98+
fnprocess(&self){
99+
self.generate();//~ ERROR: unused `Result` that must be used
100+
}
101+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
error: unused `Result` that must be used
2+
--> $DIR/must_use-result-unit-uninhabited.rs:80:5
3+
|
4+
LL | result_unit_unit();
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 _ = result_unit_unit();
16+
| +++++++
17+
18+
error: unused `Result` that must be used
19+
--> $DIR/must_use-result-unit-uninhabited.rs:84:5
20+
|
21+
LL | result_unit_myuninhabited_nonexhaustive();
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 _ = result_unit_myuninhabited_nonexhaustive();
28+
| +++++++
29+
30+
error: unused `Result` that must be used
31+
--> $DIR/must_use-result-unit-uninhabited.rs:86:5
32+
|
33+
LL | result_unit_assoctype(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 _ = result_unit_assoctype(S2);
40+
| +++++++
41+
42+
error: unused `Result` that must be used
43+
--> $DIR/must_use-result-unit-uninhabited.rs:88:5
44+
|
45+
LL | S2.method_use_assoc_type();
46+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
47+
|
48+
= note: this `Result` may be an `Err` variant, which should be handled
49+
help: use `let _ = ...` to ignore the resulting value
50+
|
51+
LL | let _ = S2.method_use_assoc_type();
52+
| +++++++
53+
54+
error: unused `ControlFlow` that must be used
55+
--> $DIR/must_use-result-unit-uninhabited.rs:90:5
56+
|
57+
LL | controlflow_unit();
58+
| ^^^^^^^^^^^^^^^^^^
59+
|
60+
help: use `let _ = ...` to ignore the resulting value
61+
|
62+
LL | let _ = controlflow_unit();
63+
| +++++++
64+
65+
error: unused `Result` that must be used
66+
--> $DIR/must_use-result-unit-uninhabited.rs:99:9
67+
|
68+
LL | self.generate();
69+
| ^^^^^^^^^^^^^^^
70+
|
71+
= note: this `Result` may be an `Err` variant, which should be handled
72+
help: use `let _ = ...` to ignore the resulting value
73+
|
74+
LL | let _ = self.generate();
75+
| +++++++
76+
77+
error: aborting due to 6 previous errors
78+

0 commit comments

Comments
 (0)