Skip to content

Commit 6100bb5

Browse files
committed
auto merge of #5804 : alexcrichton/rust/issue-3266, r=graydon
This leaves the default lint modes at `warn`, but now the unused variable and dead assignment warnings are configurable on a per-item basis. As described in #3266, this just involved carrying around a couple ids to pass over to `span_lint`. I personally would prefer to keep the `_` prefix as well. This closes #3266.
2 parents 80b6bbd + 3e67085 commit 6100bb5

File tree

3 files changed

+82
-60
lines changed

3 files changed

+82
-60
lines changed

src/librustc/middle/lint.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ pub enum lint {
8383

8484
legacy_modes,
8585

86-
// FIXME(#3266)--make liveness warnings lintable
87-
// unused_variable,
88-
// dead_assignment
86+
unused_variable,
87+
dead_assignment,
8988
}
9089

9190
pub fn level_to_str(lv: level) -> &'static str {
@@ -257,21 +256,19 @@ pub fn get_lint_dict() -> LintDict {
257256
default: deny
258257
}),
259258

260-
/* FIXME(#3266)--make liveness warnings lintable
261-
(@~"unused_variable",
262-
@LintSpec {
259+
(~"unused_variable",
260+
LintSpec {
263261
lint: unused_variable,
264262
desc: "detect variables which are not used in any way",
265263
default: warn
266-
}),
264+
}),
267265

268-
(@~"dead_assignment",
269-
@LintSpec {
266+
(~"dead_assignment",
267+
LintSpec {
270268
lint: dead_assignment,
271269
desc: "detect assignments that will never be read",
272270
default: warn
273-
}),
274-
*/
271+
}),
275272
];
276273
let mut map = HashMap::new();
277274
do vec::consume(v) |_, (k, v)| {

src/librustc/middle/liveness.rs

+48-31
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105

106106
use core::prelude::*;
107107

108+
use middle::lint::{unused_variable, dead_assignment};
108109
use middle::pat_util;
109110
use middle::ty;
110111
use middle::typeck;
@@ -118,6 +119,7 @@ use core::ptr;
118119
use core::to_str;
119120
use core::uint;
120121
use core::vec;
122+
use core::util::with;
121123
use syntax::ast::*;
122124
use syntax::codemap::span;
123125
use syntax::parse::token::special_idents;
@@ -169,6 +171,7 @@ pub fn check_crate(tcx: ty::ctxt,
169171
visit_local: visit_local,
170172
visit_expr: visit_expr,
171173
visit_arm: visit_arm,
174+
visit_item: visit_item,
172175
.. *visit::default_visitor()
173176
});
174177

@@ -177,7 +180,8 @@ pub fn check_crate(tcx: ty::ctxt,
177180
method_map,
178181
variable_moves_map,
179182
capture_map,
180-
last_use_map);
183+
last_use_map,
184+
0);
181185
visit::visit_crate(*crate, initial_maps, visitor);
182186
tcx.sess.abort_if_errors();
183187
return last_use_map;
@@ -269,13 +273,16 @@ struct IrMaps {
269273
capture_info_map: HashMap<node_id, @~[CaptureInfo]>,
270274
var_kinds: ~[VarKind],
271275
lnks: ~[LiveNodeKind],
276+
277+
cur_item: node_id,
272278
}
273279

274280
fn IrMaps(tcx: ty::ctxt,
275281
method_map: typeck::method_map,
276282
variable_moves_map: moves::VariableMovesMap,
277283
capture_map: moves::CaptureMap,
278-
last_use_map: last_use_map)
284+
last_use_map: last_use_map,
285+
cur_item: node_id)
279286
-> IrMaps {
280287
IrMaps {
281288
tcx: tcx,
@@ -289,7 +296,8 @@ fn IrMaps(tcx: ty::ctxt,
289296
variable_map: HashMap::new(),
290297
capture_info_map: HashMap::new(),
291298
var_kinds: ~[],
292-
lnks: ~[]
299+
lnks: ~[],
300+
cur_item: cur_item,
293301
}
294302
}
295303

@@ -394,6 +402,12 @@ pub impl IrMaps {
394402
}
395403
}
396404

405+
fn visit_item(item: @item, &&self: @mut IrMaps, v: vt<@mut IrMaps>) {
406+
do with(&mut self.cur_item, item.id) {
407+
visit::visit_item(item, self, v)
408+
}
409+
}
410+
397411
fn visit_fn(fk: &visit::fn_kind,
398412
decl: &fn_decl,
399413
body: &blk,
@@ -409,7 +423,8 @@ fn visit_fn(fk: &visit::fn_kind,
409423
self.method_map,
410424
self.variable_moves_map,
411425
self.capture_map,
412-
self.last_use_map);
426+
self.last_use_map,
427+
self.cur_item);
413428

414429
debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint);
415430

@@ -692,17 +707,19 @@ pub impl Liveness {
692707
}
693708
}
694709

695-
fn pat_bindings(&self, pat: @pat, f: &fn(LiveNode, Variable, span)) {
710+
fn pat_bindings(&self, pat: @pat,
711+
f: &fn(LiveNode, Variable, span, node_id)) {
696712
let def_map = self.tcx.def_map;
697713
do pat_util::pat_bindings(def_map, pat) |_bm, p_id, sp, _n| {
698714
let ln = self.live_node(p_id, sp);
699715
let var = self.variable(p_id, sp);
700-
f(ln, var, sp);
716+
f(ln, var, sp, p_id);
701717
}
702718
}
703719

704720
fn arm_pats_bindings(&self,
705-
pats: &[@pat], f: &fn(LiveNode, Variable, span)) {
721+
pats: &[@pat],
722+
f: &fn(LiveNode, Variable, span, node_id)) {
706723
// only consider the first pattern; any later patterns must have
707724
// the same bindings, and we also consider the first pattern to be
708725
// the "authoratative" set of ids
@@ -718,7 +735,7 @@ pub impl Liveness {
718735
fn define_bindings_in_arm_pats(&self, pats: &[@pat],
719736
succ: LiveNode) -> LiveNode {
720737
let mut succ = succ;
721-
do self.arm_pats_bindings(pats) |ln, var, _sp| {
738+
do self.arm_pats_bindings(pats) |ln, var, _sp, _id| {
722739
self.init_from_succ(ln, succ);
723740
self.define(ln, var);
724741
succ = ln;
@@ -1509,8 +1526,8 @@ fn check_local(local: @local, &&self: @Liveness, vt: vt<@Liveness>) {
15091526
// should not be live at this point.
15101527

15111528
debug!("check_local() with no initializer");
1512-
do self.pat_bindings(local.node.pat) |ln, var, sp| {
1513-
if !self.warn_about_unused(sp, ln, var) {
1529+
do self.pat_bindings(local.node.pat) |ln, var, sp, id| {
1530+
if !self.warn_about_unused(sp, id, ln, var) {
15141531
match self.live_on_exit(ln, var) {
15151532
None => { /* not live: good */ }
15161533
Some(lnk) => {
@@ -1528,8 +1545,8 @@ fn check_local(local: @local, &&self: @Liveness, vt: vt<@Liveness>) {
15281545
}
15291546

15301547
fn check_arm(arm: &arm, &&self: @Liveness, vt: vt<@Liveness>) {
1531-
do self.arm_pats_bindings(arm.pats) |ln, var, sp| {
1532-
self.warn_about_unused(sp, ln, var);
1548+
do self.arm_pats_bindings(arm.pats) |ln, var, sp, id| {
1549+
self.warn_about_unused(sp, id, ln, var);
15331550
}
15341551
visit::visit_arm(arm, self, vt);
15351552
}
@@ -1691,14 +1708,14 @@ pub impl Liveness {
16911708
let ln = self.live_node(expr.id, expr.span);
16921709
let var = self.variable(nid, expr.span);
16931710
self.check_for_reassignment(ln, var, expr.span);
1694-
self.warn_about_dead_assign(expr.span, ln, var);
1711+
self.warn_about_dead_assign(expr.span, expr.id, ln, var);
16951712
}
16961713
def => {
16971714
match relevant_def(def) {
16981715
Some(nid) => {
16991716
let ln = self.live_node(expr.id, expr.span);
17001717
let var = self.variable(nid, expr.span);
1701-
self.warn_about_dead_assign(expr.span, ln, var);
1718+
self.warn_about_dead_assign(expr.span, expr.id, ln, var);
17021719
}
17031720
None => {}
17041721
}
@@ -1715,7 +1732,7 @@ pub impl Liveness {
17151732
}
17161733

17171734
fn check_for_reassignments_in_pat(@self, pat: @pat) {
1718-
do self.pat_bindings(pat) |ln, var, sp| {
1735+
do self.pat_bindings(pat) |ln, var, sp, _id| {
17191736
self.check_for_reassignment(ln, var, sp);
17201737
}
17211738
}
@@ -1861,21 +1878,21 @@ pub impl Liveness {
18611878
do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
18621879
|_bm, p_id, sp, _n| {
18631880
let var = self.variable(p_id, sp);
1864-
self.warn_about_unused(sp, entry_ln, var);
1881+
self.warn_about_unused(sp, p_id, entry_ln, var);
18651882
}
18661883
}
18671884
}
18681885

18691886
fn warn_about_unused_or_dead_vars_in_pat(@self, pat: @pat) {
1870-
do self.pat_bindings(pat) |ln, var, sp| {
1871-
if !self.warn_about_unused(sp, ln, var) {
1872-
self.warn_about_dead_assign(sp, ln, var);
1887+
do self.pat_bindings(pat) |ln, var, sp, id| {
1888+
if !self.warn_about_unused(sp, id, ln, var) {
1889+
self.warn_about_dead_assign(sp, id, ln, var);
18731890
}
18741891
}
18751892
}
18761893

1877-
fn warn_about_unused(@self, sp: span, ln: LiveNode, var: Variable)
1878-
-> bool {
1894+
fn warn_about_unused(@self, sp: span, id: node_id,
1895+
ln: LiveNode, var: Variable) -> bool {
18791896
if !self.used_on_entry(ln, var) {
18801897
for self.should_warn(var).each |name| {
18811898

@@ -1889,27 +1906,27 @@ pub impl Liveness {
18891906
};
18901907

18911908
if is_assigned {
1892-
// FIXME(#3266)--make liveness warnings lintable
1893-
self.tcx.sess.span_warn(
1894-
sp, fmt!("variable `%s` is assigned to, \
1909+
self.tcx.sess.span_lint(unused_variable, id,
1910+
self.ir.cur_item, sp,
1911+
fmt!("variable `%s` is assigned to, \
18951912
but never used", **name));
18961913
} else {
1897-
// FIXME(#3266)--make liveness warnings lintable
1898-
self.tcx.sess.span_warn(
1899-
sp, fmt!("unused variable: `%s`", **name));
1914+
self.tcx.sess.span_lint(unused_variable, id,
1915+
self.ir.cur_item, sp,
1916+
fmt!("unused variable: `%s`", **name));
19001917
}
19011918
}
19021919
return true;
19031920
}
19041921
return false;
19051922
}
19061923

1907-
fn warn_about_dead_assign(@self, sp: span, ln: LiveNode, var: Variable) {
1924+
fn warn_about_dead_assign(@self, sp: span, id: node_id,
1925+
ln: LiveNode, var: Variable) {
19081926
if self.live_on_exit(ln, var).is_none() {
19091927
for self.should_warn(var).each |name| {
1910-
// FIXME(#3266)--make liveness warnings lintable
1911-
self.tcx.sess.span_warn(
1912-
sp,
1928+
self.tcx.sess.span_lint(dead_assignment, id,
1929+
self.ir.cur_item, sp,
19131930
fmt!("value assigned to `%s` is never read", **name));
19141931
}
19151932
}

src/test/compile-fail/liveness-unused.rs

+26-18
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,57 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#[deny(unused_variable)];
12+
#[deny(dead_assignment)];
13+
1114
fn f1(x: int) {
12-
//~^ WARNING unused variable: `x`
15+
//~^ ERROR unused variable: `x`
1316
}
1417

1518
fn f1b(x: &mut int) {
16-
//~^ WARNING unused variable: `x`
19+
//~^ ERROR unused variable: `x`
1720
}
1821

22+
#[allow(unused_variable)]
23+
fn f1c(x: int) {}
24+
1925
fn f2() {
2026
let x = 3;
21-
//~^ WARNING unused variable: `x`
27+
//~^ ERROR unused variable: `x`
2228
}
2329

2430
fn f3() {
2531
let mut x = 3;
26-
//~^ WARNING variable `x` is assigned to, but never used
32+
//~^ ERROR variable `x` is assigned to, but never used
2733
x += 4;
28-
//~^ WARNING value assigned to `x` is never read
34+
//~^ ERROR value assigned to `x` is never read
2935
}
3036

3137
fn f3b() {
3238
let mut z = 3;
33-
//~^ WARNING variable `z` is assigned to, but never used
39+
//~^ ERROR variable `z` is assigned to, but never used
3440
loop {
3541
z += 4;
3642
}
3743
}
3844

45+
#[allow(unused_variable)]
46+
fn f3c() {
47+
let mut z = 3;
48+
loop { z += 4; }
49+
}
50+
51+
#[allow(unused_variable)]
52+
#[allow(dead_assignment)]
53+
fn f3d() {
54+
let mut x = 3;
55+
x += 4;
56+
}
57+
3958
fn f4() {
4059
match Some(3) {
4160
Some(i) => {
42-
//~^ WARNING unused variable: `i`
61+
//~^ ERROR unused variable: `i`
4362
}
4463
None => {}
4564
}
@@ -57,16 +76,5 @@ fn f4b() -> int {
5776
}
5877
}
5978

60-
// leave this in here just to trigger compile-fail:
61-
struct r {
62-
x: (),
63-
}
64-
65-
impl Drop for r {
66-
fn finalize(&self) {}
67-
}
68-
6979
fn main() {
70-
let x = r { x: () };
71-
|| { copy x; }; //~ ERROR copying a value of non-copyable type
7280
}

0 commit comments

Comments
 (0)