Skip to content

Commit 7a6a25e

Browse files
Rollup merge of #85324 - FabianWolff:issue-85255, r=varkor
Warn about unused `pub` fields in non-`pub` structs This pull request fixes #85255. The current implementation of dead code analysis is too prudent because it marks all `pub` fields of structs as live, even though they cannot be accessed from outside of the current crate if the struct itself only has restricted or private visibility. I have changed this behavior to take the containing struct's visibility into account when looking at field visibility and liveness. This also makes dead code warnings more consistent; consider the example given in #85255: ```rust struct Foo { a: i32, pub b: i32, } struct Bar; impl Bar { fn a(&self) -> i32 { 5 } pub fn b(&self) -> i32 { 6 } } fn main() { let _ = Foo { a: 1, b: 2 }; let _ = Bar; } ``` Current nightly already warns about `Bar::b()`, even though it is `pub` (but `Bar` is not). It should therefore also warn about `Foo::b`, which it does with the changes in this PR.
2 parents f851f97 + 46d55d6 commit 7a6a25e

File tree

6 files changed

+87
-22
lines changed

6 files changed

+87
-22
lines changed

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

+29-20
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct MarkSymbolVisitor<'tcx> {
4444
repr_has_repr_c: bool,
4545
in_pat: bool,
4646
inherited_pub_visibility: bool,
47+
pub_visibility: bool,
4748
ignore_variant_stack: Vec<DefId>,
4849
// maps from tuple struct constructors to tuple struct items
4950
struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
@@ -188,27 +189,33 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
188189

189190
fn visit_node(&mut self, node: Node<'tcx>) {
190191
let had_repr_c = self.repr_has_repr_c;
191-
self.repr_has_repr_c = false;
192192
let had_inherited_pub_visibility = self.inherited_pub_visibility;
193+
let had_pub_visibility = self.pub_visibility;
194+
self.repr_has_repr_c = false;
193195
self.inherited_pub_visibility = false;
196+
self.pub_visibility = false;
194197
match node {
195-
Node::Item(item) => match item.kind {
196-
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
197-
let def = self.tcx.adt_def(item.def_id);
198-
self.repr_has_repr_c = def.repr.c();
198+
Node::Item(item) => {
199+
self.pub_visibility = item.vis.node.is_pub();
199200

200-
intravisit::walk_item(self, &item);
201-
}
202-
hir::ItemKind::Enum(..) => {
203-
self.inherited_pub_visibility = item.vis.node.is_pub();
201+
match item.kind {
202+
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
203+
let def = self.tcx.adt_def(item.def_id);
204+
self.repr_has_repr_c = def.repr.c();
204205

205-
intravisit::walk_item(self, &item);
206-
}
207-
hir::ItemKind::ForeignMod { .. } => {}
208-
_ => {
209-
intravisit::walk_item(self, &item);
206+
intravisit::walk_item(self, &item);
207+
}
208+
hir::ItemKind::Enum(..) => {
209+
self.inherited_pub_visibility = self.pub_visibility;
210+
211+
intravisit::walk_item(self, &item);
212+
}
213+
hir::ItemKind::ForeignMod { .. } => {}
214+
_ => {
215+
intravisit::walk_item(self, &item);
216+
}
210217
}
211-
},
218+
}
212219
Node::TraitItem(trait_item) => {
213220
intravisit::walk_trait_item(self, trait_item);
214221
}
@@ -220,8 +227,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
220227
}
221228
_ => {}
222229
}
223-
self.repr_has_repr_c = had_repr_c;
230+
self.pub_visibility = had_pub_visibility;
224231
self.inherited_pub_visibility = had_inherited_pub_visibility;
232+
self.repr_has_repr_c = had_repr_c;
225233
}
226234

227235
fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &[hir::ExprField<'_>]) {
@@ -259,10 +267,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
259267
) {
260268
let has_repr_c = self.repr_has_repr_c;
261269
let inherited_pub_visibility = self.inherited_pub_visibility;
262-
let live_fields = def
263-
.fields()
264-
.iter()
265-
.filter(|f| has_repr_c || inherited_pub_visibility || f.vis.node.is_pub());
270+
let pub_visibility = self.pub_visibility;
271+
let live_fields = def.fields().iter().filter(|f| {
272+
has_repr_c || (pub_visibility && (inherited_pub_visibility || f.vis.node.is_pub()))
273+
});
266274
self.live_symbols.extend(live_fields.map(|f| f.hir_id));
267275

268276
intravisit::walk_struct_def(self, def);
@@ -500,6 +508,7 @@ fn find_live<'tcx>(
500508
repr_has_repr_c: false,
501509
in_pat: false,
502510
inherited_pub_visibility: false,
511+
pub_visibility: false,
503512
ignore_variant_stack: vec![],
504513
struct_constructors,
505514
};

Diff for: src/test/ui/cast/issue-84213.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct Something {
66

77
fn main() {
88
let mut something = Something { field: 1337 };
9+
let _ = something.field;
910

1011
let _pointer_to_something = &something as *const Something;
1112
//~^ ERROR: non-primitive cast

Diff for: src/test/ui/cast/issue-84213.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct Something {
66

77
fn main() {
88
let mut something = Something { field: 1337 };
9+
let _ = something.field;
910

1011
let _pointer_to_something = something as *const Something;
1112
//~^ ERROR: non-primitive cast

Diff for: src/test/ui/cast/issue-84213.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0605]: non-primitive cast: `Something` as `*const Something`
2-
--> $DIR/issue-84213.rs:10:33
2+
--> $DIR/issue-84213.rs:11:33
33
|
44
LL | let _pointer_to_something = something as *const Something;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
@@ -10,7 +10,7 @@ LL | let _pointer_to_something = &something as *const Something;
1010
| ^
1111

1212
error[E0605]: non-primitive cast: `Something` as `*mut Something`
13-
--> $DIR/issue-84213.rs:13:37
13+
--> $DIR/issue-84213.rs:14:37
1414
|
1515
LL | let _mut_pointer_to_something = something as *mut Something;
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast

Diff for: src/test/ui/lint/dead-code/issue-85255.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Unused `pub` fields in non-`pub` structs should also trigger dead code warnings.
2+
// check-pass
3+
4+
#![warn(dead_code)]
5+
6+
struct Foo {
7+
a: i32, //~ WARNING: field is never read
8+
pub b: i32, //~ WARNING: field is never read
9+
}
10+
11+
struct Bar;
12+
13+
impl Bar {
14+
fn a(&self) -> i32 { 5 } //~ WARNING: associated function is never used
15+
pub fn b(&self) -> i32 { 6 } //~ WARNING: associated function is never used
16+
}
17+
18+
19+
fn main() {
20+
let _ = Foo { a: 1, b: 2 };
21+
let _ = Bar;
22+
}

Diff for: src/test/ui/lint/dead-code/issue-85255.stderr

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
warning: field is never read: `a`
2+
--> $DIR/issue-85255.rs:7:5
3+
|
4+
LL | a: i32,
5+
| ^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/issue-85255.rs:4:9
9+
|
10+
LL | #![warn(dead_code)]
11+
| ^^^^^^^^^
12+
13+
warning: field is never read: `b`
14+
--> $DIR/issue-85255.rs:8:5
15+
|
16+
LL | pub b: i32,
17+
| ^^^^^^^^^^
18+
19+
warning: associated function is never used: `a`
20+
--> $DIR/issue-85255.rs:14:8
21+
|
22+
LL | fn a(&self) -> i32 { 5 }
23+
| ^
24+
25+
warning: associated function is never used: `b`
26+
--> $DIR/issue-85255.rs:15:12
27+
|
28+
LL | pub fn b(&self) -> i32 { 6 }
29+
| ^
30+
31+
warning: 4 warnings emitted
32+

0 commit comments

Comments
 (0)