diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d13b16dce8986..c46378374104c 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -117,7 +117,7 @@ use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; use syntax::symbol::keywords; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; use hir::Expr; use hir; @@ -1363,8 +1363,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) { match local.init { - Some(_) => { - this.warn_about_unused_or_dead_vars_in_pat(&local.pat); + Some(ref init_expr) => { + this.warn_about_unused_or_dead_vars_in_pat(&local.pat, init_expr.span); }, None => { this.pat_bindings(&local.pat, |this, ln, var, sp, id| { @@ -1388,19 +1388,21 @@ fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) { fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { match expr.node { - hir::ExprAssign(ref l, _) => { - this.check_place(&l); + hir::ExprAssign(ref l, ref r) => { + let msp = MultiSpan::from_spans(vec![l.span, r.span]); + this.check_place(&l, msp); - intravisit::walk_expr(this, expr); - } - - hir::ExprAssignOp(_, ref l, _) => { - if !this.tables.is_method_call(expr) { - this.check_place(&l); + intravisit::walk_expr(this, expr); } - intravisit::walk_expr(this, expr); - } + hir::ExprAssignOp(_, ref l, ref r) => { + if !this.tables.is_method_call(expr) { + let msp = MultiSpan::from_spans(vec![l.span, r.span]); + this.check_place(&l, msp); + } + + intravisit::walk_expr(this, expr); + } hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => { for input in inputs { @@ -1410,7 +1412,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { // Output operands must be places for (o, output) in ia.outputs.iter().zip(outputs) { if !o.is_indirect { - this.check_place(output); + this.check_place(output, MultiSpan::from_span(output.span)); } this.visit_expr(output); } @@ -1435,7 +1437,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn check_place(&mut self, expr: &'tcx Expr) { + fn check_place(&mut self, expr: &'tcx Expr, msp: MultiSpan) { match expr.node { hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { if let Def::Local(nid) = path.def { @@ -1445,7 +1447,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // as being used. let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); - self.warn_about_dead_assign(expr.span, expr.id, ln, var); + self.warn_about_dead_assign(msp, expr.id, ln, var); } } _ => { @@ -1482,10 +1484,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - fn warn_about_unused_or_dead_vars_in_pat(&mut self, pat: &hir::Pat) { + fn warn_about_unused_or_dead_vars_in_pat(&mut self, pat: &hir::Pat, assign_span: Span) { self.pat_bindings(pat, |this, ln, var, sp, id| { if !this.warn_about_unused(sp, id, ln, var) { - this.warn_about_dead_assign(sp, id, ln, var); + let msp = MultiSpan::from_spans(vec![sp, assign_span]); + this.warn_about_dead_assign(msp, id, ln, var); } }) } @@ -1538,16 +1541,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn warn_about_dead_assign(&self, - sp: Span, + msp: MultiSpan, id: NodeId, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { - self.report_dead_assign(id, sp, var, false); + self.report_dead_assign(id, msp, var, false); } } - fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) { + fn report_dead_assign>(&self, id: NodeId, sp: S, + var: Variable, is_argument: bool) { if let Some(name) = self.should_warn(var) { if is_argument { self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index 35fe5479406df..1cfd5aa0a5f4c 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -29,7 +29,7 @@ warning: value assigned to `hours_are_suns` is never read --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:32:9 | LL | hours_are_suns = false; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ ^^^^^ | note: lint level defined here --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9 diff --git a/src/test/compile-fail/liveness-dead.rs b/src/test/ui/lint/liveness-dead.rs similarity index 69% rename from src/test/compile-fail/liveness-dead.rs rename to src/test/ui/lint/liveness-dead.rs index ddd8fc68c43a3..9c3ba178561c3 100644 --- a/src/test/compile-fail/liveness-dead.rs +++ b/src/test/ui/lint/liveness-dead.rs @@ -8,15 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + #![allow(dead_code)] -#![deny(unused_assignments)] +#![warn(unused_assignments)] fn f1(x: &mut isize) { *x = 1; // no error } fn f2() { - let mut x: isize = 3; //~ ERROR: value assigned to `x` is never read + let (mut x, y) = (3, 4); //~ WARN: value assigned to `x` is never read x = 4; x.clone(); } @@ -24,17 +26,17 @@ fn f2() { fn f3() { let mut x: isize = 3; x.clone(); - x = 4; //~ ERROR: value assigned to `x` is never read + x = 4; //~ WARN: value assigned to `x` is never read } -fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read +fn f4(mut x: i32) { //~ WARN: value passed to `x` is never read x = 4; x.clone(); } fn f5(mut x: i32) { x.clone(); - x = 4; //~ ERROR: value assigned to `x` is never read + x = 4; //~ WARN: value assigned to `x` is never read } fn main() {} diff --git a/src/test/ui/lint/liveness-dead.stderr b/src/test/ui/lint/liveness-dead.stderr new file mode 100644 index 0000000000000..1f7c98f6027ce --- /dev/null +++ b/src/test/ui/lint/liveness-dead.stderr @@ -0,0 +1,30 @@ +warning: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:21:10 + | +LL | let (mut x, y) = (3, 4); //~ WARN: value assigned to `x` is never read + | ^^^^^ ^^^^^^ + | +note: lint level defined here + --> $DIR/liveness-dead.rs:14:9 + | +LL | #![warn(unused_assignments)] + | ^^^^^^^^^^^^^^^^^^ + +warning: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:29:5 + | +LL | x = 4; //~ WARN: value assigned to `x` is never read + | ^ ^ + +warning: value passed to `x` is never read + --> $DIR/liveness-dead.rs:32:7 + | +LL | fn f4(mut x: i32) { //~ WARN: value passed to `x` is never read + | ^^^^^ + +warning: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:39:5 + | +LL | x = 4; //~ WARN: value assigned to `x` is never read + | ^ ^ + diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/ui/lint/liveness-unused.rs similarity index 75% rename from src/test/compile-fail/liveness-unused.rs rename to src/test/ui/lint/liveness-unused.rs index d056d6be806f7..a18240f660bcd 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/ui/lint/liveness-unused.rs @@ -8,19 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![warn(unused)] -#![deny(unused_variables)] -#![deny(unused_assignments)] +// must-compile-successfully + +#![warn(unused_variables, unused_assignments, unreachable_code)] #![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] use std::ops::AddAssign; fn f1(x: isize) { - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } fn f1b(x: &mut isize) { - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } #[allow(unused_variables)] @@ -28,24 +28,24 @@ fn f1c(x: isize) {} fn f1d() { let x: isize; - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } fn f2() { let x = 3; - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } fn f3() { let mut x = 3; - //~^ ERROR variable `x` is assigned to, but never used + //~^ WARN variable `x` is assigned to, but never used x += 4; - //~^ ERROR value assigned to `x` is never read + //~^ WARN value assigned to `x` is never read } fn f3b() { let mut z = 3; - //~^ ERROR variable `z` is assigned to, but never used + //~^ WARN variable `z` is assigned to, but never used loop { z += 4; } @@ -67,7 +67,7 @@ fn f3d() { fn f4() { match Some(3) { Some(i) => { - //~^ ERROR unused variable: `i` + //~^ WARN unused variable: `i` } None => {} } @@ -87,19 +87,19 @@ fn f4b() -> isize { fn f5a() { for x in 1..10 { } - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } fn f5b() { for (x, _) in [1, 2, 3].iter().enumerate() { } - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` } fn f5c() { for (_, x) in [1, 2, 3].iter().enumerate() { - //~^ ERROR unused variable: `x` + //~^ WARN unused variable: `x` continue; - drop(*x as i32); //~ WARNING unreachable statement + drop(*x as i32); //~ WARN unreachable statement } } @@ -120,10 +120,10 @@ fn f6() { // ensure an error shows up for x even if lhs of an overloaded add assign let x; - //~^ ERROR variable `x` is assigned to, but never used + //~^ WARN variable `x` is assigned to, but never used *({ - x = 0; //~ ERROR value assigned to `x` is never read + x = 0; //~ WARN value assigned to `x` is never read &mut v }) += 1; } diff --git a/src/test/ui/lint/liveness-unused.stderr b/src/test/ui/lint/liveness-unused.stderr new file mode 100644 index 0000000000000..3f8b598985b20 --- /dev/null +++ b/src/test/ui/lint/liveness-unused.stderr @@ -0,0 +1,108 @@ +warning: unreachable statement + --> $DIR/liveness-unused.rs:102:9 + | +LL | drop(*x as i32); //~ WARN unreachable statement + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/liveness-unused.rs:13:47 + | +LL | #![warn(unused_variables, unused_assignments, unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:18:7 + | +LL | fn f1(x: isize) { + | ^ help: consider using `_x` instead + | +note: lint level defined here + --> $DIR/liveness-unused.rs:13:9 + | +LL | #![warn(unused_variables, unused_assignments, unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:22:8 + | +LL | fn f1b(x: &mut isize) { + | ^ help: consider using `_x` instead + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:30:9 + | +LL | let x: isize; + | ^ help: consider using `_x` instead + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:35:9 + | +LL | let x = 3; + | ^ help: consider using `_x` instead + +warning: variable `x` is assigned to, but never used + --> $DIR/liveness-unused.rs:40:9 + | +LL | let mut x = 3; + | ^^^^^ + | + = note: consider using `_x` instead + +warning: value assigned to `x` is never read + --> $DIR/liveness-unused.rs:42:5 + | +LL | x += 4; + | ^ ^ + | +note: lint level defined here + --> $DIR/liveness-unused.rs:13:27 + | +LL | #![warn(unused_variables, unused_assignments, unreachable_code)] + | ^^^^^^^^^^^^^^^^^^ + +warning: variable `z` is assigned to, but never used + --> $DIR/liveness-unused.rs:47:9 + | +LL | let mut z = 3; + | ^^^^^ + | + = note: consider using `_z` instead + +warning: unused variable: `i` + --> $DIR/liveness-unused.rs:69:12 + | +LL | Some(i) => { + | ^ help: consider using `_i` instead + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:89:9 + | +LL | for x in 1..10 { } + | ^ help: consider using `_x` instead + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:94:10 + | +LL | for (x, _) in [1, 2, 3].iter().enumerate() { } + | ^ help: consider using `_x` instead + +warning: unused variable: `x` + --> $DIR/liveness-unused.rs:99:13 + | +LL | for (_, x) in [1, 2, 3].iter().enumerate() { + | ^ help: consider using `_x` instead + +warning: variable `x` is assigned to, but never used + --> $DIR/liveness-unused.rs:122:9 + | +LL | let x; + | ^ + | + = note: consider using `_x` instead + +warning: value assigned to `x` is never read + --> $DIR/liveness-unused.rs:126:9 + | +LL | x = 0; //~ WARN value assigned to `x` is never read + | ^ ^ +