Skip to content

Commit 17a892b

Browse files
committed
consider Result<T, !>/ControlFlow<!, T> the same as T for must_use lint
(or more accurately `Result<T, Uninhabited>`/`ControlFlow<Uninhabited, T>`). This generalizes a previous change where we only did this for `T = ()`.
1 parent f6839c9 commit 17a892b

File tree

3 files changed

+42
-28
lines changed

3 files changed

+42
-28
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
259259
Opaque(Box<Self>),
260260
TraitObject(Box<Self>),
261261
TupleElement(Vec<(usize, Self)>),
262+
/// `Result<T, Uninhabited>`
263+
Result(Box<Self>),
264+
/// `ControlFlow<Uninhabited, T>`
265+
ControlFlow(Box<Self>),
262266
Array(Box<Self>, u64),
263267
/// The root of the unused_closures lint.
264268
Closure(Span),
@@ -291,21 +295,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
291295
is_ty_must_use(cx, pinned_ty, expr, span)
292296
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
293297
}
294-
// Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`).
298+
// Consider `Result<T, Uninhabited>` (e.g. `Result<(), !>`) equivalent to `T`.
295299
ty::Adt(def, args)
296300
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
297-
&& args.type_at(0).is_unit()
298301
&& is_uninhabited(args.type_at(1)) =>
299302
{
300-
Some(MustUsePath::Suppressed)
303+
let ok_ty = args.type_at(0);
304+
is_ty_must_use(cx, ok_ty, expr, span).map(Box::new).map(MustUsePath::Result)
301305
}
302-
// Suppress warnings on `ControlFlow<Uninhabited, ()>` (e.g. `ControlFlow<!, ()>`).
306+
// Consider `ControlFlow<Uninhabited, T>` (e.g. `ControlFlow<!, ()>`) equivalent to `T`.
303307
ty::Adt(def, args)
304308
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
305-
&& args.type_at(1).is_unit()
306309
&& is_uninhabited(args.type_at(0)) =>
307310
{
308-
Some(MustUsePath::Suppressed)
311+
let continue_ty = args.type_at(1);
312+
is_ty_must_use(cx, continue_ty, expr, span)
313+
.map(Box::new)
314+
.map(MustUsePath::ControlFlow)
309315
}
310316
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
311317
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
@@ -498,6 +504,32 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
498504
);
499505
}
500506
}
507+
MustUsePath::Result(path) => {
508+
let descr_post =
509+
&format!(" in a `Result` with an uninhabited error{descr_post}");
510+
emit_must_use_untranslated(
511+
cx,
512+
path,
513+
descr_pre,
514+
descr_post,
515+
plural_len,
516+
true,
517+
expr_is_from_block,
518+
);
519+
}
520+
MustUsePath::ControlFlow(path) => {
521+
let descr_post =
522+
&format!(" in a `ControlFlow` with an uninhabited break {descr_post}");
523+
emit_must_use_untranslated(
524+
cx,
525+
path,
526+
descr_pre,
527+
descr_post,
528+
plural_len,
529+
true,
530+
expr_is_from_block,
531+
);
532+
}
501533
MustUsePath::Array(path, len) => {
502534
let descr_pre = &format!("{descr_pre}array{plural_suffix} of ");
503535
emit_must_use_untranslated(

tests/ui/lint/unused/must_use-result-unit-uninhabited.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ fn main() {
9393
result_unit_unit(); //~ ERROR: unused `Result` that must be used
9494
result_unit_infallible();
9595
result_unit_never();
96-
result_must_use_never(); //~ ERROR: unused `Result` that must be used
97-
result_struct_never(); //~ ERROR: unused `Result` that must be used
96+
result_must_use_never(); //~ ERROR: unused `MustUse` in a `Result` with an uninhabited error that must be used
97+
result_struct_never();
9898
result_unit_myuninhabited();
9999
result_unit_myuninhabited_nonexhaustive(); //~ ERROR: unused `Result` that must be used
100100
result_unit_assoctype(S1);

tests/ui/lint/unused/must_use-result-unit-uninhabited.stderr

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,11 @@ help: use `let _ = ...` to ignore the resulting value
1515
LL | let _ = result_unit_unit();
1616
| +++++++
1717

18-
error: unused `Result` that must be used
18+
error: unused `MustUse` in a `Result` with an uninhabited error that must be used
1919
--> $DIR/must_use-result-unit-uninhabited.rs:96:5
2020
|
2121
LL | result_must_use_never();
2222
| ^^^^^^^^^^^^^^^^^^^^^^^
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_must_use_never();
28-
| +++++++
29-
30-
error: unused `Result` that must be used
31-
--> $DIR/must_use-result-unit-uninhabited.rs:97:5
32-
|
33-
LL | result_struct_never();
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_struct_never();
40-
| +++++++
4123

4224
error: unused `Result` that must be used
4325
--> $DIR/must_use-result-unit-uninhabited.rs:99:5
@@ -98,5 +80,5 @@ help: use `let _ = ...` to ignore the resulting value
9880
LL | let _ = self.generate();
9981
| +++++++
10082

101-
error: aborting due to 8 previous errors
83+
error: aborting due to 7 previous errors
10284

0 commit comments

Comments
 (0)