Liveness analysis for everybody

Perform liveness analysis for every body instead of limiting it to fns.
This commit is contained in:
Tomasz Miąsko 2020-09-28 00:00:00 +00:00
parent 381b445ff5
commit 924e8aaaf2
8 changed files with 174 additions and 42 deletions

View File

@ -90,12 +90,12 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::*;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
use rustc_index::vec::IndexVec;
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
@ -318,49 +318,38 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
NestedVisitorMap::OnlyBodies(self.tcx.hir())
}
fn visit_fn(
&mut self,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
sp: Span,
id: HirId,
) {
debug!("visit_fn {:?}", id);
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
debug!("visit_body {:?}", body.id());
// swap in a new set of IR maps for this function body:
let def_id = self.tcx.hir().local_def_id(id);
let mut fn_maps = IrMaps::new(self.tcx);
// swap in a new set of IR maps for this body
let mut maps = IrMaps::new(self.tcx);
let hir_id = maps.tcx.hir().body_owner(body.id());
let def_id = maps.tcx.hir().local_def_id(hir_id);
// Don't run unused pass for #[derive()]
if let FnKind::Method(..) = fk {
let parent = self.tcx.hir().get_parent_item(id);
if let Some(Node::Item(i)) = self.tcx.hir().find(parent) {
if i.attrs.iter().any(|a| self.tcx.sess.check_name(a, sym::automatically_derived)) {
if let Some(parent) = self.tcx.parent(def_id.to_def_id()) {
if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) {
if self.tcx.has_attr(parent, sym::automatically_derived) {
return;
}
}
}
debug!("creating fn_maps: {:p}", &fn_maps);
let body = self.tcx.hir().body(body_id);
if let Some(upvars) = self.tcx.upvars_mentioned(def_id) {
if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) {
for (&var_hir_id, _upvar) in upvars {
let var_name = self.tcx.hir().name(var_hir_id);
fn_maps.add_variable(Upvar(var_hir_id, var_name));
let var_name = maps.tcx.hir().name(var_hir_id);
maps.add_variable(Upvar(var_hir_id, var_name));
}
}
// gather up the various local variables, significant expressions,
// and so forth:
intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
intravisit::walk_body(&mut maps, body);
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, def_id);
let entry_ln = lsets.compute(&body, sp, id);
lsets.log_liveness(entry_ln, id);
let mut lsets = Liveness::new(&mut maps, def_id);
let entry_ln = lsets.compute(&body, hir_id);
lsets.log_liveness(entry_ln, body.id().hir_id);
// check for various error conditions
lsets.visit_body(body);
@ -845,8 +834,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.rwu_table.assign_unpacked(idx, rwu);
}
fn compute(&mut self, body: &hir::Body<'_>, span: Span, id: hir::HirId) -> LiveNode {
debug!("compute: using id for body, {:?}", body.value);
fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode {
debug!("compute: for body {:?}", body.id().hir_id);
// # Liveness of captured variables
//
@ -890,7 +879,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
return succ;
}
let ty = self.typeck_results.node_type(id);
let ty = self.typeck_results.node_type(hir_id);
match ty.kind() {
ty::Closure(_def_id, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => {}
@ -899,7 +888,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
},
ty::Generator(..) => return succ,
_ => {
span_bug!(span, "{} has upvars so it should have a closure type: {:?}", id, ty);
span_bug!(
body.value.span,
"{} has upvars so it should have a closure type: {:?}",
hir_id,
ty
);
}
};

View File

@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, unused)]
type Array = [u32; { let x = 2; 5 }];

View File

@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, unused)]
#[repr(u8)]
enum Foo {

View File

@ -1,6 +1,7 @@
// run-pass
// revisions: stock precise
#![allow(unused)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
// `x` is always moved into the final value and is not dropped inside the initializer.

View File

@ -0,0 +1,63 @@
// check-pass
#![warn(unused)]
#![allow(unreachable_code)]
pub static A: i32 = {
let mut i = 0;
let mut a = 0; //~ WARN variable `a` is assigned to, but never used
while i < 10 {
i += 1;
a += 1;
}
i
};
pub const B: u32 = {
let mut b = 1;
b += 1; //~ WARN value assigned to `b` is never read
b = 42;
b
};
pub enum E {
V1 = {
let e = 1; //~ WARN unused variable: `e`
1
},
V2 = {
let _f = 10;
2
}
}
pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] {
//~^ WARN unused variable: `s`
//~| WARN unused variable: `z`
x
}
pub trait T {
const T: usize = {
let mut t = 10;
t = t + t; //~ WARN value assigned to `t` is never read
20
};
}
impl T for String {
const T: usize = {
let w = 10; //~ WARN unused variable: `w`
loop {
break;
let _ = w;
}
44
};
}
fn main() {
let _ = [(); {
let z = 42; //~ WARN unused variable: `z`
35
}];
}

View File

@ -0,0 +1,68 @@
warning: variable `a` is assigned to, but never used
--> $DIR/liveness-consts.rs:7:9
|
LL | let mut a = 0;
| ^^^^^
|
note: the lint level is defined here
--> $DIR/liveness-consts.rs:2:9
|
LL | #![warn(unused)]
| ^^^^^^
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
= note: consider using `_a` instead
warning: value assigned to `b` is never read
--> $DIR/liveness-consts.rs:17:5
|
LL | b += 1;
| ^
|
note: the lint level is defined here
--> $DIR/liveness-consts.rs:2:9
|
LL | #![warn(unused)]
| ^^^^^^
= note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]`
= help: maybe it is overwritten before being read?
warning: unused variable: `e`
--> $DIR/liveness-consts.rs:24:13
|
LL | let e = 1;
| ^ help: if this is intentional, prefix it with an underscore: `_e`
warning: unused variable: `s`
--> $DIR/liveness-consts.rs:33:24
|
LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] {
| ^ help: if this is intentional, prefix it with an underscore: `_s`
warning: unused variable: `z`
--> $DIR/liveness-consts.rs:33:55
|
LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] {
| ^ help: if this is intentional, prefix it with an underscore: `_z`
warning: unused variable: `z`
--> $DIR/liveness-consts.rs:60:13
|
LL | let z = 42;
| ^ help: if this is intentional, prefix it with an underscore: `_z`
warning: value assigned to `t` is never read
--> $DIR/liveness-consts.rs:42:9
|
LL | t = t + t;
| ^
|
= help: maybe it is overwritten before being read?
warning: unused variable: `w`
--> $DIR/liveness-consts.rs:49:13
|
LL | let w = 10;
| ^ help: if this is intentional, prefix it with an underscore: `_w`
warning: 8 warnings emitted

View File

@ -12,7 +12,7 @@ pub trait T: Sized {
impl T for u32 {
const N: usize = {
let a = 0; // FIXME should warn about unused variable
let a = 0; //~ WARN unused variable: `a`
4
};

View File

@ -1,8 +1,8 @@
warning: unused variable: `b`
--> $DIR/liveness-derive.rs:20:13
warning: unused variable: `a`
--> $DIR/liveness-derive.rs:15:13
|
LL | let b = 16;
| ^ help: if this is intentional, prefix it with an underscore: `_b`
LL | let a = 0;
| ^ help: if this is intentional, prefix it with an underscore: `_a`
|
note: the lint level is defined here
--> $DIR/liveness-derive.rs:6:9
@ -11,5 +11,11 @@ LL | #![warn(unused)]
| ^^^^^^
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
warning: 1 warning emitted
warning: unused variable: `b`
--> $DIR/liveness-derive.rs:20:13
|
LL | let b = 16;
| ^ help: if this is intentional, prefix it with an underscore: `_b`
warning: 2 warnings emitted