about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2017-07-30 19:08:26 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2017-08-05 22:02:45 +0200
commit59fcac6fa977630640fb79c4c97486b14ca66cee (patch)
tree0185b5841f10fc0f08d3a5c058496f2662993ca2
parent46fe8e99665d6a210f6dc16590127ee808e60366 (diff)
downloadrust-59fcac6fa977630640fb79c4c97486b14ca66cee.tar.gz
rust-59fcac6fa977630640fb79c4c97486b14ca66cee.zip
Improve dead code detection for unions
-rw-r--r--src/librustc/hir/intravisit.rs2
-rw-r--r--src/librustc/middle/dead.rs46
2 files changed, 32 insertions, 16 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 57198d8ca0b..e751241669d 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 91d25c680d8..2f0ee8d8f2f 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<ast::NodeId> {
 struct DeadVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     live_symbols: Box<FxHashSet<ast::NodeId>>,
+    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);
 }