about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-06-30 21:57:28 +0200
committerGitHub <noreply@github.com>2019-06-30 21:57:28 +0200
commit2b313b1d321797e7c161c40b102c963cf53dd7ac (patch)
tree272ea627ebd4991252d799390669e20d9e10bb59
parentc779f4e89c0abe949195a28418be11fddf77b5a3 (diff)
parent76f5b50716d609d09e53cf537be54a42bd0f007d (diff)
downloadrust-2b313b1d321797e7c161c40b102c963cf53dd7ac.tar.gz
rust-2b313b1d321797e7c161c40b102c963cf53dd7ac.zip
Rollup merge of #62235 - varkor:must_use-adt-components, r=Centril
Extend the `#[must_use]` lint to arrays

Based on top of https://github.com/rust-lang/rust/pull/62228.

r? @Centril
-rw-r--r--src/librustc_lint/unused.rs48
-rw-r--r--src/test/ui/lint/must_use-array.rs47
-rw-r--r--src/test/ui/lint/must_use-array.stderr44
3 files changed, 127 insertions, 12 deletions
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 3fbd7db765b..2db2e0bc0da 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 00000000000..97825dd2f6c
--- /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<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
+}
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 00000000000..a6dbd8e93d4
--- /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
+