diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 57198d8ca0b7..e751241669da 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -877,7 +877,7 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &' pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { visitor.visit_id(struct_definition.id()); - walk_list!(visitor, visit_struct_field, struct_definition.fields()); + walk_list!(visitor, visit_struct_field, struct_definition.fields().iter().rev()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 91d25c680d87..2f0ee8d8f2fb 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -422,6 +422,7 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option { struct DeadVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, live_symbols: Box>, + need_check_next_union_field: bool, } impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { @@ -537,6 +538,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } } + fn visit_variant_data(&mut self, + s: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _parent_id: ast::NodeId, + _: syntax_pos::Span) { + self.need_check_next_union_field = true; + intravisit::walk_struct_def(self, s) + } + fn visit_variant(&mut self, variant: &'tcx hir::Variant, g: &'tcx hir::Generics, @@ -557,23 +568,24 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } fn visit_struct_field(&mut self, field: &'tcx hir::StructField) { - if self.should_warn_about_field(&field) { - let did = self.tcx.hir.get_parent_did(field.id); - if if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { - match self.tcx.hir.find(node_id) { - Some(hir_map::NodeItem(item)) => match item.node { - Item_::ItemUnion(_, _) => false, - _ => true, - }, - _ => true, - } - } else { - true - } { + if self.need_check_next_union_field { + if self.should_warn_about_field(&field) { self.warn_dead_code(field.id, field.span, field.name, "field"); + } else { + let did = self.tcx.hir.get_parent_did(field.id); + if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { + match self.tcx.hir.find(node_id) { + Some(hir_map::NodeItem(item)) => match item.node { + // If this is an union's field, it means all previous fields + // have been used as well so no need to check further. + Item_::ItemUnion(_, _) => self.need_check_next_union_field = false, + _ => {} + }, + _ => {} + } + } } } - intravisit::walk_struct_field(self, field); } @@ -615,6 +627,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); - let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; + let mut visitor = DeadVisitor { + tcx: tcx, + live_symbols: live_symbols, + need_check_next_union_field: true, + }; intravisit::walk_crate(&mut visitor, krate); }