Skip to content
Permalink
Browse files

Extend #[must_use] lint to arrays

  • Loading branch information...
varkor committed Jun 29, 2019
1 parent 400fd60 commit 76f5b50716d609d09e53cf537be54a42bd0f007d
Showing with 127 additions and 12 deletions.
  1. +36 −12 src/librustc_lint/unused.rs
  2. +47 −0 src/test/ui/lint/must_use-array.rs
  3. +44 −0 src/test/ui/lint/must_use-array.stderr
@@ -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,32 +133,39 @@ 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)
{
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;
for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
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,
}
}
@@ -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<dyn T>); 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
}
@@ -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

0 comments on commit 76f5b50

Please sign in to comment.
You can’t perform that action at this time.