Skip to content

Commit 5af8b5f

Browse files
committed
Extend dead code lint to detect more unused enum variants
1 parent f813f97 commit 5af8b5f

File tree

4 files changed

+73
-7
lines changed

4 files changed

+73
-7
lines changed

src/librustc/middle/dead.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
4747
struct_has_extern_repr: bool,
4848
ignore_non_const_paths: bool,
4949
inherited_pub_visibility: bool,
50+
ignore_variant_stack: Vec<ast::NodeId>,
5051
}
5152

5253
impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
@@ -59,6 +60,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
5960
struct_has_extern_repr: false,
6061
ignore_non_const_paths: false,
6162
inherited_pub_visibility: false,
63+
ignore_variant_stack: vec![],
6264
}
6365
}
6466

@@ -79,7 +81,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
7981
def::DefPrimTy(_) => (),
8082
def::DefVariant(enum_id, variant_id, _) => {
8183
self.check_def_id(enum_id);
82-
self.check_def_id(variant_id);
84+
if !self.ignore_variant_stack.contains(&variant_id.node) {
85+
self.check_def_id(variant_id);
86+
}
8387
}
8488
_ => {
8589
self.check_def_id(def.def_id());
@@ -271,6 +275,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
271275
visit::walk_expr(self, expr);
272276
}
273277

278+
fn visit_arm(&mut self, arm: &ast::Arm) {
279+
if arm.pats.len() == 1 {
280+
let pat = &*arm.pats[0];
281+
let variants = pat_util::necessary_variants(&self.tcx.def_map, pat);
282+
283+
// Inside the body, ignore constructions of variants
284+
// necessary for the pattern to match. Those construction sites
285+
// can't be reached unless the variant is constructed elsewhere.
286+
let len = self.ignore_variant_stack.len();
287+
self.ignore_variant_stack.push_all(&*variants);
288+
visit::walk_arm(self, arm);
289+
self.ignore_variant_stack.truncate(len);
290+
} else {
291+
visit::walk_arm(self, arm);
292+
}
293+
}
294+
274295
fn visit_pat(&mut self, pat: &ast::Pat) {
275296
let def_map = &self.tcx.def_map;
276297
match pat.node {
@@ -392,6 +413,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
392413
worklist.push(*id);
393414
}
394415
for id in reachable_symbols {
416+
// Reachable variants can be dead, because we warn about
417+
// variants never constructed, not variants never used.
418+
if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) {
419+
continue;
420+
}
395421
worklist.push(*id);
396422
}
397423

src/librustc/middle/pat_util.rs

+24
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,27 @@ pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path {
189189
span: DUMMY_SP,
190190
})
191191
}
192+
193+
/// Return variants that are necessary to exist for the pattern to match.
194+
pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec<ast::NodeId> {
195+
let mut variants = vec![];
196+
walk_pat(pat, |p| {
197+
match p.node {
198+
ast::PatEnum(_, _) |
199+
ast::PatIdent(_, _, None) |
200+
ast::PatStruct(..) => {
201+
match dm.borrow().get(&p.id) {
202+
Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
203+
variants.push(id.node);
204+
}
205+
_ => ()
206+
}
207+
}
208+
_ => ()
209+
}
210+
true
211+
});
212+
variants.sort();
213+
variants.dedup();
214+
variants
215+
}

src/librustc_typeck/check/cast.rs

-6
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ enum CastError {
9999
NeedViaInt,
100100
NeedViaUsize,
101101
NonScalar,
102-
RefToMutPtr
103102
}
104103

105104
impl<'tcx> CastCheck<'tcx> {
@@ -161,11 +160,6 @@ impl<'tcx> CastCheck<'tcx> {
161160
fcx.infcx().ty_to_string(self.cast_ty))
162161
}, self.expr_ty, None);
163162
}
164-
CastError::RefToMutPtr => {
165-
span_err!(fcx.tcx().sess, self.span, E0188,
166-
"cannot cast an immutable reference to a \
167-
mutable pointer");
168-
}
169163
}
170164
}
171165

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(dead_code)]
12+
13+
#[derive(Clone)]
14+
enum Enum {
15+
Variant1, //~ ERROR: variant is never used
16+
Variant2,
17+
}
18+
19+
fn main() {
20+
let e = Enum::Variant2;
21+
e.clone();
22+
}

0 commit comments

Comments
 (0)