Skip to content

Commit 90f54d0

Browse files
Improve union unused field detection
1 parent 59fcac6 commit 90f54d0

File tree

3 files changed

+43
-42
lines changed

3 files changed

+43
-42
lines changed

src/librustc/hir/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
877877

878878
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
879879
visitor.visit_id(struct_definition.id());
880-
walk_list!(visitor, visit_struct_field, struct_definition.fields().iter().rev());
880+
walk_list!(visitor, visit_struct_field, struct_definition.fields());
881881
}
882882

883883
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {

src/librustc/middle/dead.rs

+26-29
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,24 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
189189
self.struct_has_extern_repr = had_extern_repr;
190190
self.inherited_pub_visibility = had_inherited_pub_visibility;
191191
}
192+
193+
fn mark_as_used_if_union(&mut self, did: DefId) {
194+
if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
195+
match self.tcx.hir.find(node_id) {
196+
Some(hir_map::NodeItem(item)) => match item.node {
197+
Item_::ItemUnion(ref variant, _) => {
198+
if variant.fields().len() > 1 {
199+
for field in variant.fields() {
200+
self.live_symbols.insert(field.id);
201+
}
202+
}
203+
}
204+
_ => {}
205+
},
206+
_ => {}
207+
}
208+
}
209+
}
192210
}
193211

194212
impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
@@ -221,6 +239,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
221239
hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
222240
let def = self.tables.qpath_def(qpath, expr.id);
223241
self.handle_definition(def);
242+
self.mark_as_used_if_union(def.def_id());
243+
}
244+
hir::ExprPath(ref qpath @ hir::QPath::Resolved(..)) => {
245+
let def = self.tables.qpath_def(qpath, expr.id);
246+
self.mark_as_used_if_union(def.def_id());
224247
}
225248
hir::ExprMethodCall(..) => {
226249
self.lookup_and_handle_method(expr.id);
@@ -422,7 +445,6 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
422445
struct DeadVisitor<'a, 'tcx: 'a> {
423446
tcx: TyCtxt<'a, 'tcx, 'tcx>,
424447
live_symbols: Box<FxHashSet<ast::NodeId>>,
425-
need_check_next_union_field: bool,
426448
}
427449

428450
impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
@@ -538,16 +560,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
538560
}
539561
}
540562

541-
fn visit_variant_data(&mut self,
542-
s: &'tcx hir::VariantData,
543-
_: ast::Name,
544-
_: &'tcx hir::Generics,
545-
_parent_id: ast::NodeId,
546-
_: syntax_pos::Span) {
547-
self.need_check_next_union_field = true;
548-
intravisit::walk_struct_def(self, s)
549-
}
550-
551563
fn visit_variant(&mut self,
552564
variant: &'tcx hir::Variant,
553565
g: &'tcx hir::Generics,
@@ -568,23 +580,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
568580
}
569581

570582
fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
571-
if self.need_check_next_union_field {
572-
if self.should_warn_about_field(&field) {
573-
self.warn_dead_code(field.id, field.span, field.name, "field");
574-
} else {
575-
let did = self.tcx.hir.get_parent_did(field.id);
576-
if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
577-
match self.tcx.hir.find(node_id) {
578-
Some(hir_map::NodeItem(item)) => match item.node {
579-
// If this is an union's field, it means all previous fields
580-
// have been used as well so no need to check further.
581-
Item_::ItemUnion(_, _) => self.need_check_next_union_field = false,
582-
_ => {}
583-
},
584-
_ => {}
585-
}
586-
}
587-
}
583+
if self.should_warn_about_field(&field) {
584+
self.warn_dead_code(field.id, field.span,
585+
field.name, "field");
588586
}
589587
intravisit::walk_struct_field(self, field);
590588
}
@@ -630,7 +628,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
630628
let mut visitor = DeadVisitor {
631629
tcx: tcx,
632630
live_symbols: live_symbols,
633-
need_check_next_union_field: true,
634631
};
635632
intravisit::walk_crate(&mut visitor, krate);
636633
}

src/test/ui/union-fields.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,24 @@
1010

1111
#![deny(dead_code)]
1212

13-
union U {
14-
x: u32,
15-
y: f32,
13+
union U1 {
14+
a: u8, // should not be reported
15+
b: u8, // should not be reported
16+
c: u8, // should be reported
1617
}
17-
18-
struct V {
19-
x: u32,
20-
y: u32,
18+
union U2 {
19+
a: u8, // should be reported
20+
b: u8, // should not be reported
21+
c: u8, // should not be reported
2122
}
23+
union NoDropLike { a: u8 } // should be reported as unused
2224

2325
fn main() {
24-
let u = U { x: 0x3f800000 };
25-
let _f = unsafe { u.y };
26-
let v = V { x: 0, y: 0 };
27-
println!("{}", v.x);
28-
}
26+
let u = U1 { a: 0 };
27+
let _a = unsafe { u.b };
2928

29+
let u = U2 { c: 0 };
30+
let _b = unsafe { u.b };
31+
32+
let _u = NoDropLike { a: 10 };
33+
}

0 commit comments

Comments
 (0)