Skip to content

Commit da27551

Browse files
committed
emit only one note per unused struct field
1 parent 5fb8a39 commit da27551

File tree

3 files changed

+96
-36
lines changed

3 files changed

+96
-36
lines changed

Diff for: compiler/rustc_passes/src/dead.rs

+51-36
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
164164
if let (Res::Local(id_l), Res::Local(id_r)) = (
165165
typeck_results.qpath_res(qpath_l, lhs.hir_id),
166166
typeck_results.qpath_res(qpath_r, rhs.hir_id),
167-
) {
168-
if id_l == id_r {
169-
return true;
170-
}
167+
) && id_l == id_r
168+
{
169+
return true;
171170
}
172171
return false;
173172
}
@@ -183,10 +182,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
183182
}
184183
}
185184

186-
if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind {
187-
if check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
185+
if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind
186+
&& check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
188187
&& !assign.span.from_expansion()
189-
{
188+
{
190189
let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
191190
self.tcx.struct_span_lint_hir(
192191
lint::builtin::DEAD_CODE,
@@ -201,7 +200,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
201200
.emit();
202201
},
203202
)
204-
}
205203
}
206204
}
207205

@@ -251,33 +249,33 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
251249
return false;
252250
}
253251

254-
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
255-
if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
256-
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
257-
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
258-
if let Some(adt_def_id) = adt_def.did().as_local() {
259-
self.ignored_derived_traits
260-
.entry(adt_def_id)
261-
.or_default()
262-
.push((trait_of, impl_of));
263-
}
264-
}
265-
return true;
252+
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
253+
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
254+
{
255+
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
256+
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
257+
&& let Some(adt_def_id) = adt_def.did().as_local()
258+
{
259+
self.ignored_derived_traits
260+
.entry(adt_def_id)
261+
.or_default()
262+
.push((trait_of, impl_of));
266263
}
264+
return true;
267265
}
268266
}
269267

270268
return false;
271269
}
272270

273271
fn visit_node(&mut self, node: Node<'tcx>) {
274-
if let Some(item_def_id) = match node {
275-
Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()),
276-
_ => None,
277-
} {
278-
if self.should_ignore_item(item_def_id) {
272+
match node {
273+
Node::ImplItem(hir::ImplItem { def_id, .. })
274+
if self.should_ignore_item(def_id.to_def_id()) =>
275+
{
279276
return;
280277
}
278+
_ => (),
281279
}
282280

283281
let had_repr_c = self.repr_has_repr_c;
@@ -534,10 +532,10 @@ fn check_item<'tcx>(
534532
}
535533
DefKind::Struct => {
536534
let item = tcx.hir().item(id);
537-
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind {
538-
if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
539-
struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
540-
}
535+
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
536+
&& let Some(ctor_hir_id) = variant_data.ctor_hir_id()
537+
{
538+
struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
541539
}
542540
}
543541
DefKind::GlobalAsm => {
@@ -630,6 +628,7 @@ struct DeadVisitor<'tcx> {
630628
tcx: TyCtxt<'tcx>,
631629
live_symbols: &'tcx FxHashSet<LocalDefId>,
632630
ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
631+
ignored_struct_def: FxHashSet<LocalDefId>,
633632
}
634633

635634
impl<'tcx> DeadVisitor<'tcx> {
@@ -677,10 +676,10 @@ impl<'tcx> DeadVisitor<'tcx> {
677676
let inherent_impls = self.tcx.inherent_impls(def_id);
678677
for &impl_did in inherent_impls.iter() {
679678
for item_did in self.tcx.associated_item_def_ids(impl_did) {
680-
if let Some(def_id) = item_did.as_local() {
681-
if self.live_symbols.contains(&def_id) {
682-
return true;
683-
}
679+
if let Some(def_id) = item_did.as_local()
680+
&& self.live_symbols.contains(&def_id)
681+
{
682+
return true;
684683
}
685684
}
686685
}
@@ -698,9 +697,20 @@ impl<'tcx> DeadVisitor<'tcx> {
698697
self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
699698
let def_id = self.tcx.hir().local_def_id(id);
700699
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
701-
let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
700+
let mut err = lint.build(&format!("{descr} is never {participle}: `{name}`"));
702701
let hir = self.tcx.hir();
703-
if let Some(encl_scope) = hir.get_enclosing_scope(id)
702+
let is_field_in_same_struct =
703+
if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(id)
704+
&& let Some(parent_node) = self.tcx.hir().find(parent_hir_id)
705+
&& let Node::Item(hir::Item{kind: hir::ItemKind::Struct(..), ..}) = parent_node
706+
&& let Some(did) = self.tcx.hir().opt_local_def_id(parent_hir_id)
707+
{
708+
!self.ignored_struct_def.insert(did)
709+
} else {
710+
false
711+
};
712+
if !is_field_in_same_struct
713+
&& let Some(encl_scope) = hir.get_enclosing_scope(id)
704714
&& let Some(encl_def_id) = hir.opt_local_def_id(encl_scope)
705715
&& let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id)
706716
{
@@ -857,7 +867,12 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
857867

858868
fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
859869
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
860-
let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
870+
let mut visitor = DeadVisitor {
871+
tcx,
872+
live_symbols,
873+
ignored_derived_traits,
874+
ignored_struct_def: FxHashSet::default(),
875+
};
861876
let (module, _, module_id) = tcx.hir().get_module(module);
862877
// Do not use an ItemLikeVisitor since we may want to skip visiting some items
863878
// when a surrounding one is warned against or `_`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![forbid(dead_code)]
2+
3+
#[derive(Debug)]
4+
pub struct Whatever {
5+
pub field0: (),
6+
field1: (), //~ERROR field is never read: `field1
7+
field2: (), //~ERROR field is never read: `field2
8+
field3: (), //~ERROR field is never read: `field3
9+
field4: (), //~ERROR field is never read: `field4
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error: field is never read: `field1`
2+
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
3+
|
4+
LL | field1: (),
5+
| ^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
9+
|
10+
LL | #![forbid(dead_code)]
11+
| ^^^^^^^^^
12+
= note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
13+
14+
error: field is never read: `field2`
15+
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:7:5
16+
|
17+
LL | field2: (),
18+
| ^^^^^^^^^^
19+
20+
error: field is never read: `field3`
21+
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:8:5
22+
|
23+
LL | field3: (),
24+
| ^^^^^^^^^^
25+
26+
error: field is never read: `field4`
27+
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:9:5
28+
|
29+
LL | field4: (),
30+
| ^^^^^^^^^^
31+
32+
error: aborting due to 4 previous errors
33+

0 commit comments

Comments
 (0)