Skip to content

Commit 76f5b50

Browse files
committed
Extend #[must_use] lint to arrays
1 parent 400fd60 commit 76f5b50

File tree

3 files changed

+127
-12
lines changed

3 files changed

+127
-12
lines changed

src/librustc_lint/unused.rs

+36-12
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
4848
}
4949

5050
let ty = cx.tables.expr_ty(&expr);
51-
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "");
51+
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false);
5252

5353
let mut fn_warned = false;
5454
let mut op_warned = false;
@@ -133,32 +133,39 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
133133
ty: Ty<'tcx>,
134134
expr: &hir::Expr,
135135
span: Span,
136-
descr_pre_path: &str,
137-
descr_post_path: &str,
136+
descr_pre: &str,
137+
descr_post: &str,
138+
plural: bool,
138139
) -> bool {
139140
if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(
140141
cx.tcx.hir().get_module_parent(expr.hir_id), ty)
141142
{
142143
return true;
143144
}
144145

146+
let plural_suffix = if plural { "s" } else { "" };
147+
145148
match ty.sty {
146149
ty::Adt(..) if ty.is_box() => {
147150
let boxed_ty = ty.boxed_ty();
148-
let descr_pre_path = &format!("{}boxed ", descr_pre_path);
149-
check_must_use_ty(cx, boxed_ty, expr, span, descr_pre_path, descr_post_path)
151+
let descr_pre = &format!("{}boxed ", descr_pre);
152+
check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural)
150153
}
151154
ty::Adt(def, _) => {
152-
check_must_use_def(cx, def.did, span, descr_pre_path, descr_post_path)
155+
check_must_use_def(cx, def.did, span, descr_pre, descr_post)
153156
}
154157
ty::Opaque(def, _) => {
155158
let mut has_emitted = false;
156159
for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
157160
if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
158161
let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
159162
let def_id = trait_ref.def_id;
160-
let descr_pre = &format!("{}implementer of ", descr_pre_path);
161-
if check_must_use_def(cx, def_id, span, descr_pre, descr_post_path) {
163+
let descr_pre = &format!(
164+
"{}implementer{} of ",
165+
descr_pre,
166+
plural_suffix,
167+
);
168+
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
162169
has_emitted = true;
163170
break;
164171
}
@@ -171,8 +178,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
171178
for predicate in binder.skip_binder().iter() {
172179
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
173180
let def_id = trait_ref.def_id;
174-
let descr_post = &format!(" trait object{}", descr_post_path);
175-
if check_must_use_def(cx, def_id, span, descr_pre_path, descr_post) {
181+
let descr_post = &format!(
182+
" trait object{}{}",
183+
plural_suffix,
184+
descr_post,
185+
);
186+
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
176187
has_emitted = true;
177188
break;
178189
}
@@ -189,14 +200,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
189200
vec![]
190201
};
191202
for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
192-
let descr_post_path = &format!(" in tuple element {}", i);
203+
let descr_post = &format!(" in tuple element {}", i);
193204
let span = *spans.get(i).unwrap_or(&span);
194-
if check_must_use_ty(cx, ty, expr, span, descr_pre_path, descr_post_path) {
205+
if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) {
195206
has_emitted = true;
196207
}
197208
}
198209
has_emitted
199210
}
211+
ty::Array(ty, len) => match len.assert_usize(cx.tcx) {
212+
// If the array is definitely non-empty, we can do `#[must_use]` checking.
213+
Some(n) if n != 0 => {
214+
let descr_pre = &format!(
215+
"{}array{} of ",
216+
descr_pre,
217+
plural_suffix,
218+
);
219+
check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true)
220+
}
221+
// Otherwise, we don't lint, to avoid false positives.
222+
_ => false,
223+
}
200224
_ => false,
201225
}
202226
}

src/test/ui/lint/must_use-array.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![deny(unused_must_use)]
2+
3+
#[must_use]
4+
struct S;
5+
6+
struct A;
7+
8+
#[must_use]
9+
trait T {}
10+
11+
impl T for A {}
12+
13+
fn empty() -> [S; 0] {
14+
[]
15+
}
16+
17+
fn singleton() -> [S; 1] {
18+
[S]
19+
}
20+
21+
fn many() -> [S; 4] {
22+
[S, S, S, S]
23+
}
24+
25+
fn array_of_impl_trait() -> [impl T; 2] {
26+
[A, A]
27+
}
28+
29+
fn impl_array() -> [(u8, Box<dyn T>); 2] {
30+
[(0, Box::new(A)), (0, Box::new(A))]
31+
}
32+
33+
fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] {
34+
[[[S], [S]]]
35+
}
36+
37+
fn main() {
38+
empty(); // ok
39+
singleton(); //~ ERROR unused array of `S` that must be used
40+
many(); //~ ERROR unused array of `S` that must be used
41+
([S], 0, ()); //~ ERROR unused array of `S` in tuple element 0 that must be used
42+
array_of_impl_trait(); //~ ERROR unused array of implementers of `T` that must be used
43+
impl_array();
44+
//~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used
45+
array_of_arrays_of_arrays();
46+
//~^ ERROR unused array of arrays of arrays of `S` that must be used
47+
}
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: unused array of `S` that must be used
2+
--> $DIR/must_use-array.rs:39:5
3+
|
4+
LL | singleton();
5+
| ^^^^^^^^^^^^
6+
|
7+
note: lint level defined here
8+
--> $DIR/must_use-array.rs:1:9
9+
|
10+
LL | #![deny(unused_must_use)]
11+
| ^^^^^^^^^^^^^^^
12+
13+
error: unused array of `S` that must be used
14+
--> $DIR/must_use-array.rs:40:5
15+
|
16+
LL | many();
17+
| ^^^^^^^
18+
19+
error: unused array of `S` in tuple element 0 that must be used
20+
--> $DIR/must_use-array.rs:41:6
21+
|
22+
LL | ([S], 0, ());
23+
| ^^^
24+
25+
error: unused array of implementers of `T` that must be used
26+
--> $DIR/must_use-array.rs:42:5
27+
|
28+
LL | array_of_impl_trait();
29+
| ^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: unused array of boxed `T` trait objects in tuple element 1 that must be used
32+
--> $DIR/must_use-array.rs:43:5
33+
|
34+
LL | impl_array();
35+
| ^^^^^^^^^^^^^
36+
37+
error: unused array of arrays of arrays of `S` that must be used
38+
--> $DIR/must_use-array.rs:45:5
39+
|
40+
LL | array_of_arrays_of_arrays();
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: aborting due to 6 previous errors
44+

0 commit comments

Comments
 (0)