about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTakayuki Maeda <takoyaki0316@gmail.com>2022-06-08 16:34:58 +0900
committerTakayuki Maeda <takoyaki0316@gmail.com>2022-06-19 18:32:56 +0900
commitda27551f3ab25b395fa96709c7a559d04748d718 (patch)
tree7cf0b40a5498041d4023fddbde4ddac3c6478fdb
parent5fb8a3926619a18a2e31627e4cdf05f16530b0eb (diff)
downloadrust-da27551f3ab25b395fa96709c7a559d04748d718.tar.gz
rust-da27551f3ab25b395fa96709c7a559d04748d718.zip
emit only one note per unused struct field
-rw-r--r--compiler/rustc_passes/src/dead.rs87
-rw-r--r--src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.rs12
-rw-r--r--src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr33
3 files changed, 96 insertions, 36 deletions
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 519fb7ea264..421c67fb6b7 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -164,10 +164,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     if let (Res::Local(id_l), Res::Local(id_r)) = (
                         typeck_results.qpath_res(qpath_l, lhs.hir_id),
                         typeck_results.qpath_res(qpath_r, rhs.hir_id),
-                    ) {
-                        if id_l == id_r {
-                            return true;
-                        }
+                    ) && id_l == id_r
+                    {
+                        return true;
                     }
                     return false;
                 }
@@ -183,10 +182,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             }
         }
 
-        if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind {
-            if check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
+        if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind
+            && check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
                 && !assign.span.from_expansion()
-            {
+        {
                 let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
                 self.tcx.struct_span_lint_hir(
                     lint::builtin::DEAD_CODE,
@@ -201,7 +200,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                         .emit();
                     },
                 )
-            }
         }
     }
 
@@ -251,19 +249,19 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 return false;
             }
 
-            if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
-                if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
-                    let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
-                    if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
-                        if let Some(adt_def_id) = adt_def.did().as_local() {
-                            self.ignored_derived_traits
-                                .entry(adt_def_id)
-                                .or_default()
-                                .push((trait_of, impl_of));
-                        }
-                    }
-                    return true;
+            if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
+                && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
+            {
+                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
+                    && let Some(adt_def_id) = adt_def.did().as_local()
+                {
+                    self.ignored_derived_traits
+                        .entry(adt_def_id)
+                        .or_default()
+                        .push((trait_of, impl_of));
                 }
+                return true;
             }
         }
 
@@ -271,13 +269,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     }
 
     fn visit_node(&mut self, node: Node<'tcx>) {
-        if let Some(item_def_id) = match node {
-            Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()),
-            _ => None,
-        } {
-            if self.should_ignore_item(item_def_id) {
+        match node {
+            Node::ImplItem(hir::ImplItem { def_id, .. })
+                if self.should_ignore_item(def_id.to_def_id()) =>
+            {
                 return;
             }
+            _ => (),
         }
 
         let had_repr_c = self.repr_has_repr_c;
@@ -534,10 +532,10 @@ fn check_item<'tcx>(
         }
         DefKind::Struct => {
             let item = tcx.hir().item(id);
-            if let hir::ItemKind::Struct(ref variant_data, _) = item.kind {
-                if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
-                    struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
-                }
+            if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
+                && let Some(ctor_hir_id) = variant_data.ctor_hir_id()
+            {
+                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
             }
         }
         DefKind::GlobalAsm => {
@@ -630,6 +628,7 @@ struct DeadVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     live_symbols: &'tcx FxHashSet<LocalDefId>,
     ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
+    ignored_struct_def: FxHashSet<LocalDefId>,
 }
 
 impl<'tcx> DeadVisitor<'tcx> {
@@ -677,10 +676,10 @@ impl<'tcx> DeadVisitor<'tcx> {
         let inherent_impls = self.tcx.inherent_impls(def_id);
         for &impl_did in inherent_impls.iter() {
             for item_did in self.tcx.associated_item_def_ids(impl_did) {
-                if let Some(def_id) = item_did.as_local() {
-                    if self.live_symbols.contains(&def_id) {
-                        return true;
-                    }
+                if let Some(def_id) = item_did.as_local()
+                    && self.live_symbols.contains(&def_id)
+                {
+                    return true;
                 }
             }
         }
@@ -698,9 +697,20 @@ impl<'tcx> DeadVisitor<'tcx> {
             self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
                 let def_id = self.tcx.hir().local_def_id(id);
                 let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-                let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
+                let mut err = lint.build(&format!("{descr} is never {participle}: `{name}`"));
                 let hir = self.tcx.hir();
-                if let Some(encl_scope) = hir.get_enclosing_scope(id)
+                let is_field_in_same_struct =
+                    if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(id)
+                        && let Some(parent_node) = self.tcx.hir().find(parent_hir_id)
+                        && let Node::Item(hir::Item{kind: hir::ItemKind::Struct(..), ..}) = parent_node
+                        && let Some(did) = self.tcx.hir().opt_local_def_id(parent_hir_id)
+                    {
+                        !self.ignored_struct_def.insert(did)
+                    } else {
+                        false
+                    };
+                if !is_field_in_same_struct
+                    && let Some(encl_scope) = hir.get_enclosing_scope(id)
                     && let Some(encl_def_id) = hir.opt_local_def_id(encl_scope)
                     && let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id)
                 {
@@ -857,7 +867,12 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
 
 fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
     let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
-    let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
+    let mut visitor = DeadVisitor {
+        tcx,
+        live_symbols,
+        ignored_derived_traits,
+        ignored_struct_def: FxHashSet::default(),
+    };
     let (module, _, module_id) = tcx.hir().get_module(module);
     // Do not use an ItemLikeVisitor since we may want to skip visiting some items
     // when a surrounding one is warned against or `_`.
diff --git a/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
new file mode 100644
index 00000000000..f5cff8ae9e5
--- /dev/null
+++ b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
@@ -0,0 +1,12 @@
+#![forbid(dead_code)]
+
+#[derive(Debug)]
+pub struct Whatever {
+    pub field0: (),
+    field1: (), //~ERROR field is never read: `field1
+    field2: (), //~ERROR field is never read: `field2
+    field3: (), //~ERROR field is never read: `field3
+    field4: (), //~ERROR field is never read: `field4
+}
+
+fn main() {}
diff --git a/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
new file mode 100644
index 00000000000..2190a0307bf
--- /dev/null
+++ b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
@@ -0,0 +1,33 @@
+error: field is never read: `field1`
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
+   |
+LL |     field1: (),
+   |     ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
+   |
+LL | #![forbid(dead_code)]
+   |           ^^^^^^^^^
+   = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+
+error: field is never read: `field2`
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:7:5
+   |
+LL |     field2: (),
+   |     ^^^^^^^^^^
+
+error: field is never read: `field3`
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:8:5
+   |
+LL |     field3: (),
+   |     ^^^^^^^^^^
+
+error: field is never read: `field4`
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:9:5
+   |
+LL |     field4: (),
+   |     ^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+