Skip to content

Commit 2fe8b01

Browse files
Rollup merge of #153191 - WaffleLapkin:shouldnt_use_trivial_tuples, r=jdonszelmann
don't emit `unused_results` lint for tuples of "trivial" types r? @jdonszelmann Fixes #153144. So it turns out #153018 had a sneaky behavior change in the way tuples are handled and the old behavior wasn't tested. Consider these tuples: ```rust ((), ()); ((), 1); ``` Neither of them is `must_use`, so they are potential candidates for `unused_results`. So the question is whatever said tuples are considered "trivial" and thus if they end up emitting `unused_results` or not. Here is a comparison table between PRs: <table> <tr><td>stable</td><td>After #153018</td><td>After this PR</td></tr><tr><td> ```rust ((), ()); // trivial ((), 1); // trivial ``` </td> <td> ```rust ((), ()); //~ warn: unused_results ((), 1); //~ warn: unused_results ``` </td> <td> ```rust ((), ()); // trivial ((), 1); //~ warn: unused_results ``` </td> </tr> <tr> <td> tuples are trivial if **any** of their fields are trivial </td> <td> tuples are never trivial </td> <td> tuples are trivial if **all** of their fields are trivial </td> </tr> </table>
2 parents 34fd06e + 8958cb9 commit 2fe8b01

File tree

3 files changed

+49
-22
lines changed

3 files changed

+49
-22
lines changed

compiler/rustc_lint/src/unused/must_use.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,6 @@ impl IsTyMustUse {
108108
_ => self,
109109
}
110110
}
111-
112-
fn yes(self) -> Option<MustUsePath> {
113-
match self {
114-
Self::Yes(must_use_path) => Some(must_use_path),
115-
_ => None,
116-
}
117-
}
118111
}
119112

120113
/// A path through a type to a `must_use` source. Contains useful info for the lint.
@@ -254,16 +247,23 @@ pub fn is_ty_must_use<'tcx>(
254247
// Default to `expr`.
255248
let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
256249

257-
let nested_must_use = tys
258-
.iter()
259-
.zip(elem_exprs)
260-
.enumerate()
261-
.filter_map(|(i, (ty, expr))| {
262-
is_ty_must_use(cx, ty, expr, simplify_uninhabited).yes().map(|path| (i, path))
263-
})
264-
.collect::<Vec<_>>();
250+
let mut all_trivial = true;
251+
let mut nested_must_use = Vec::new();
252+
253+
tys.iter().zip(elem_exprs).enumerate().for_each(|(i, (ty, expr))| {
254+
let must_use = is_ty_must_use(cx, ty, expr, simplify_uninhabited);
255+
256+
all_trivial &= matches!(must_use, IsTyMustUse::Trivial);
257+
if let IsTyMustUse::Yes(path) = must_use {
258+
nested_must_use.push((i, path));
259+
}
260+
});
265261

266-
if !nested_must_use.is_empty() {
262+
if all_trivial {
263+
// If all tuple elements are trivial, mark the whole tuple as such.
264+
// i.e. don't emit `unused_results` for types such as `((), ())`
265+
IsTyMustUse::Trivial
266+
} else if !nested_must_use.is_empty() {
267267
IsTyMustUse::Yes(MustUsePath::TupleElement(nested_must_use))
268268
} else {
269269
IsTyMustUse::No

tests/ui/lint/unused/unused-result.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
//~^ NOTE: the lint level is defined here
44
//~| NOTE: the lint level is defined here
55

6+
use std::ops::ControlFlow;
7+
68
#[must_use]
79
enum MustUse { Test }
810

911
#[must_use = "some message"]
1012
enum MustUseMsg { Test2 }
1113

14+
enum Nothing {}
15+
1216
fn foo<T>() -> T { panic!() }
1317

1418
fn bar() -> isize { return foo::<isize>(); }
@@ -39,4 +43,15 @@ fn main() {
3943
let _ = foo::<isize>();
4044
let _ = foo::<MustUse>();
4145
let _ = foo::<MustUseMsg>();
46+
47+
// "trivial" types
48+
();
49+
((), ());
50+
Ok::<(), Nothing>(());
51+
ControlFlow::<Nothing>::Continue(());
52+
((), Ok::<(), Nothing>(()), ((((), ())), ((),)));
53+
foo::<Nothing>();
54+
55+
((), 1); //~ ERROR: unused result of type `((), i32)`
56+
(1, ()); //~ ERROR: unused result of type `(i32, ())`
4257
}

tests/ui/lint/unused/unused-result.stderr

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unused `MustUse` that must be used
2-
--> $DIR/unused-result.rs:21:5
2+
--> $DIR/unused-result.rs:25:5
33
|
44
LL | foo::<MustUse>();
55
| ^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | let _ = foo::<MustUse>();
1515
| +++++++
1616

1717
error: unused `MustUseMsg` that must be used
18-
--> $DIR/unused-result.rs:22:5
18+
--> $DIR/unused-result.rs:26:5
1919
|
2020
LL | foo::<MustUseMsg>();
2121
| ^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL | let _ = foo::<MustUseMsg>();
2727
| +++++++
2828

2929
error: unused result of type `isize`
30-
--> $DIR/unused-result.rs:34:5
30+
--> $DIR/unused-result.rs:38:5
3131
|
3232
LL | foo::<isize>();
3333
| ^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL | #![deny(unused_results, unused_must_use)]
3939
| ^^^^^^^^^^^^^^
4040

4141
error: unused `MustUse` that must be used
42-
--> $DIR/unused-result.rs:35:5
42+
--> $DIR/unused-result.rs:39:5
4343
|
4444
LL | foo::<MustUse>();
4545
| ^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL | let _ = foo::<MustUse>();
5050
| +++++++
5151

5252
error: unused `MustUseMsg` that must be used
53-
--> $DIR/unused-result.rs:36:5
53+
--> $DIR/unused-result.rs:40:5
5454
|
5555
LL | foo::<MustUseMsg>();
5656
| ^^^^^^^^^^^^^^^^^^^
@@ -61,5 +61,17 @@ help: use `let _ = ...` to ignore the resulting value
6161
LL | let _ = foo::<MustUseMsg>();
6262
| +++++++
6363

64-
error: aborting due to 5 previous errors
64+
error: unused result of type `((), i32)`
65+
--> $DIR/unused-result.rs:55:5
66+
|
67+
LL | ((), 1);
68+
| ^^^^^^^^
69+
70+
error: unused result of type `(i32, ())`
71+
--> $DIR/unused-result.rs:56:5
72+
|
73+
LL | (1, ());
74+
| ^^^^^^^^
75+
76+
error: aborting due to 7 previous errors
6577

0 commit comments

Comments
 (0)