Skip to content

Commit 426b4e8

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 3161b2c commit 426b4e8

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
@@ -271,6 +271,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
271271
Opaque(Box<Self>),
272272
TraitObject(Box<Self>),
273273
TupleElement(Vec<(usize, Self)>),
274+
/// `Result<T, Uninhabited>`
275+
Result(Box<Self>),
276+
/// `ControlFlow<Uninhabited, T>`
277+
ControlFlow(Box<Self>),
274278
Array(Box<Self>, u64),
275279
/// The root of the unused_closures lint.
276280
Closure(Span),
@@ -303,21 +307,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
303307
is_ty_must_use(cx, pinned_ty, expr, span)
304308
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
305309
}
306-
// Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`).
310+
// Consider `Result<T, Uninhabited>` (e.g. `Result<(), !>`) equivalent to `T`.
307311
ty::Adt(def, args)
308312
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
309-
&& args.type_at(0).is_unit()
310313
&& is_uninhabited(args.type_at(1)) =>
311314
{
312-
Some(MustUsePath::Suppressed)
315+
let ok_ty = args.type_at(0);
316+
is_ty_must_use(cx, ok_ty, expr, span).map(Box::new).map(MustUsePath::Result)
313317
}
314-
// Suppress warnings on `ControlFlow<Uninhabited, ()>` (e.g. `ControlFlow<!, ()>`).
318+
// Consider `ControlFlow<Uninhabited, T>` (e.g. `ControlFlow<!, ()>`) equivalent to `T`.
315319
ty::Adt(def, args)
316320
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
317-
&& args.type_at(1).is_unit()
318321
&& is_uninhabited(args.type_at(0)) =>
319322
{
320-
Some(MustUsePath::Suppressed)
323+
let continue_ty = args.type_at(1);
324+
is_ty_must_use(cx, continue_ty, expr, span)
325+
.map(Box::new)
326+
.map(MustUsePath::ControlFlow)
321327
}
322328
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
323329
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
@@ -510,6 +516,32 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
510516
);
511517
}
512518
}
519+
MustUsePath::Result(path) => {
520+
let descr_post =
521+
&format!(" in a `Result` with an uninhabited error{descr_post}");
522+
emit_must_use_untranslated(
523+
cx,
524+
path,
525+
descr_pre,
526+
descr_post,
527+
plural_len,
528+
true,
529+
expr_is_from_block,
530+
);
531+
}
532+
MustUsePath::ControlFlow(path) => {
533+
let descr_post =
534+
&format!(" in a `ControlFlow` with an uninhabited break {descr_post}");
535+
emit_must_use_untranslated(
536+
cx,
537+
path,
538+
descr_pre,
539+
descr_post,
540+
plural_len,
541+
true,
542+
expr_is_from_block,
543+
);
544+
}
513545
MustUsePath::Array(path, len) => {
514546
let descr_pre = &format!("{descr_pre}array{plural_suffix} of ");
515547
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)