From 76f5b50716d609d09e53cf537be54a42bd0f007d Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 29 Jun 2019 16:23:15 +0100 Subject: [PATCH] Extend #[must_use] lint to arrays --- src/librustc_lint/unused.rs | 48 +++++++++++++++++++------- src/test/ui/lint/must_use-array.rs | 47 +++++++++++++++++++++++++ src/test/ui/lint/must_use-array.stderr | 44 +++++++++++++++++++++++ 3 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/lint/must_use-array.rs create mode 100644 src/test/ui/lint/must_use-array.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 3fbd7db765b70..2db2e0bc0da96 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", ""); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); let mut fn_warned = false; let mut op_warned = false; @@ -133,8 +133,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty: Ty<'tcx>, expr: &hir::Expr, span: Span, - descr_pre_path: &str, - descr_post_path: &str, + descr_pre: &str, + descr_post: &str, + plural: bool, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.hir().get_module_parent(expr.hir_id), ty) @@ -142,14 +143,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } + let plural_suffix = if plural { "s" } else { "" }; + match ty.sty { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); - let descr_pre_path = &format!("{}boxed ", descr_pre_path); - check_must_use_ty(cx, boxed_ty, expr, span, descr_pre_path, descr_post_path) + let descr_pre = &format!("{}boxed ", descr_pre); + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) } ty::Adt(def, _) => { - check_must_use_def(cx, def.did, span, descr_pre_path, descr_post_path) + check_must_use_def(cx, def.did, span, descr_pre, descr_post) } ty::Opaque(def, _) => { let mut has_emitted = false; @@ -157,8 +160,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; - let descr_pre = &format!("{}implementer of ", descr_pre_path); - if check_must_use_def(cx, def_id, span, descr_pre, descr_post_path) { + let descr_pre = &format!( + "{}implementer{} of ", + descr_pre, + plural_suffix, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -171,8 +178,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for predicate in binder.skip_binder().iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { let def_id = trait_ref.def_id; - let descr_post = &format!(" trait object{}", descr_post_path); - if check_must_use_def(cx, def_id, span, descr_pre_path, descr_post) { + let descr_post = &format!( + " trait object{}{}", + plural_suffix, + descr_post, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -189,14 +200,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { vec![] }; for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { - let descr_post_path = &format!(" in tuple element {}", i); + let descr_post = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_pre_path, descr_post_path) { + if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { has_emitted = true; } } has_emitted } + ty::Array(ty, len) => match len.assert_usize(cx.tcx) { + // If the array is definitely non-empty, we can do `#[must_use]` checking. + Some(n) if n != 0 => { + let descr_pre = &format!( + "{}array{} of ", + descr_pre, + plural_suffix, + ); + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + } + // Otherwise, we don't lint, to avoid false positives. + _ => false, + } _ => false, } } diff --git a/src/test/ui/lint/must_use-array.rs b/src/test/ui/lint/must_use-array.rs new file mode 100644 index 0000000000000..97825dd2f6c43 --- /dev/null +++ b/src/test/ui/lint/must_use-array.rs @@ -0,0 +1,47 @@ +#![deny(unused_must_use)] + +#[must_use] +struct S; + +struct A; + +#[must_use] +trait T {} + +impl T for A {} + +fn empty() -> [S; 0] { + [] +} + +fn singleton() -> [S; 1] { + [S] +} + +fn many() -> [S; 4] { + [S, S, S, S] +} + +fn array_of_impl_trait() -> [impl T; 2] { + [A, A] +} + +fn impl_array() -> [(u8, Box); 2] { + [(0, Box::new(A)), (0, Box::new(A))] +} + +fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] { + [[[S], [S]]] +} + +fn main() { + empty(); // ok + singleton(); //~ ERROR unused array of `S` that must be used + many(); //~ ERROR unused array of `S` that must be used + ([S], 0, ()); //~ ERROR unused array of `S` in tuple element 0 that must be used + array_of_impl_trait(); //~ ERROR unused array of implementers of `T` that must be used + impl_array(); + //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used + array_of_arrays_of_arrays(); + //~^ ERROR unused array of arrays of arrays of `S` that must be used +} diff --git a/src/test/ui/lint/must_use-array.stderr b/src/test/ui/lint/must_use-array.stderr new file mode 100644 index 0000000000000..a6dbd8e93d4d3 --- /dev/null +++ b/src/test/ui/lint/must_use-array.stderr @@ -0,0 +1,44 @@ +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:39:5 + | +LL | singleton(); + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-array.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:40:5 + | +LL | many(); + | ^^^^^^^ + +error: unused array of `S` in tuple element 0 that must be used + --> $DIR/must_use-array.rs:41:6 + | +LL | ([S], 0, ()); + | ^^^ + +error: unused array of implementers of `T` that must be used + --> $DIR/must_use-array.rs:42:5 + | +LL | array_of_impl_trait(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused array of boxed `T` trait objects in tuple element 1 that must be used + --> $DIR/must_use-array.rs:43:5 + | +LL | impl_array(); + | ^^^^^^^^^^^^^ + +error: unused array of arrays of arrays of `S` that must be used + --> $DIR/must_use-array.rs:45:5 + | +LL | array_of_arrays_of_arrays(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors +