diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2015-03-13 18:12:05 +0530 |
|---|---|---|
| committer | Manish Goregaokar <manishsmail@gmail.com> | 2015-03-13 18:12:05 +0530 |
| commit | 0d37323fd3052ca893caa7ec7b1a7263a1cd0656 (patch) | |
| tree | c9bf947cd7b86cd3a9d86984d7413a391c54bf3f | |
| parent | 0e4b8d6117d767d78c61ff5416572ae5eaaa7440 (diff) | |
| parent | b042ffc4a768c2bd6d7588b1b2f47af22669c2cb (diff) | |
| download | rust-0d37323fd3052ca893caa7ec7b1a7263a1cd0656.tar.gz rust-0d37323fd3052ca893caa7ec7b1a7263a1cd0656.zip | |
Rollup merge of #21468 - sanxiyn:dead-variant, r=
This implements a wish suggested in #17410, detecting enum variants that are never constructed, even in the presence of `#[derive(Clone)]`. The implementation is general and not specific to `#[derive(Clone)]`. r? @jakub-
| -rw-r--r-- | src/librustc/middle/dead.rs | 28 | ||||
| -rw-r--r-- | src/librustc/middle/pat_util.rs | 24 | ||||
| -rw-r--r-- | src/libtest/lib.rs | 1 | ||||
| -rw-r--r-- | src/test/compile-fail/lint-dead-code-variant.rs | 42 |
4 files changed, 94 insertions, 1 deletions
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 5efea66ab0c..09378f2c973 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -47,6 +47,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, + ignore_variant_stack: Vec<ast::NodeId>, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { @@ -59,6 +60,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { struct_has_extern_repr: false, ignore_non_const_paths: false, inherited_pub_visibility: false, + ignore_variant_stack: vec![], } } @@ -79,7 +81,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { def::DefPrimTy(_) => (), def::DefVariant(enum_id, variant_id, _) => { self.check_def_id(enum_id); - self.check_def_id(variant_id); + if !self.ignore_variant_stack.contains(&variant_id.node) { + self.check_def_id(variant_id); + } } _ => { self.check_def_id(def.def_id()); @@ -278,6 +282,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { visit::walk_expr(self, expr); } + fn visit_arm(&mut self, arm: &ast::Arm) { + if arm.pats.len() == 1 { + let pat = &*arm.pats[0]; + let variants = pat_util::necessary_variants(&self.tcx.def_map, pat); + + // Inside the body, ignore constructions of variants + // necessary for the pattern to match. Those construction sites + // can't be reached unless the variant is constructed elsewhere. + let len = self.ignore_variant_stack.len(); + self.ignore_variant_stack.push_all(&*variants); + visit::walk_arm(self, arm); + self.ignore_variant_stack.truncate(len); + } else { + visit::walk_arm(self, arm); + } + } + fn visit_pat(&mut self, pat: &ast::Pat) { let def_map = &self.tcx.def_map; match pat.node { @@ -397,6 +418,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt, worklist.push(*id); } for id in reachable_symbols { + // Reachable variants can be dead, because we warn about + // variants never constructed, not variants never used. + if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) { + continue; + } worklist.push(*id); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index c5abff3b963..7f3b00eb3e6 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -155,3 +155,27 @@ pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path { span: DUMMY_SP, }) } + +/// Return variants that are necessary to exist for the pattern to match. +pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec<ast::NodeId> { + let mut variants = vec![]; + walk_pat(pat, |p| { + match p.node { + ast::PatEnum(_, _) | + ast::PatIdent(_, _, None) | + ast::PatStruct(..) => { + match dm.borrow().get(&p.id) { + Some(&DefVariant(_, id, _)) => { + variants.push(id.node); + } + _ => () + } + } + _ => () + } + true + }); + variants.sort(); + variants.dedup(); + variants +} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 19da658ed4f..80d5ab5baf3 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -121,6 +121,7 @@ impl fmt::Display for TestName { #[derive(Clone, Copy)] enum NamePadding { PadNone, + #[allow(dead_code)] PadOnLeft, PadOnRight, } diff --git a/src/test/compile-fail/lint-dead-code-variant.rs b/src/test/compile-fail/lint-dead-code-variant.rs new file mode 100644 index 00000000000..6146be65e38 --- /dev/null +++ b/src/test/compile-fail/lint-dead-code-variant.rs @@ -0,0 +1,42 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(dead_code)] + +#[derive(Copy)] +enum Enum { + Variant1, //~ ERROR: variant is never used + Variant2, + Variant3, +} + +fn copy(e: Enum) -> Enum { + use Enum::*; + match e { + Variant1 => Variant1, + Variant2 => Variant2, + Variant3 => Variant3, + } +} + +fn max(e: Enum) -> Enum { + use Enum::*; + match e { + Variant1 => Variant3, + Variant2 => Variant3, + Variant3 => Variant3, + } +} + +fn main() { + let e = Enum::Variant2; + copy(e); + max(e); +} |
