Skip to content

Liveness analysis for everybody #77281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 28 additions & 34 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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 => {}
Expand All @@ -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
);
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-block-non-item-statement-3.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, unused)]

type Array = [u32; { let x = 2; 5 }];

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-block-non-item-statement-rpass.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, unused)]

#[repr(u8)]
enum Foo {
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/consts/control-flow/drop-pass.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
63 changes: 63 additions & 0 deletions src/test/ui/liveness/liveness-consts.rs
Original file line number Diff line number Diff line change
@@ -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
}];
}
68 changes: 68 additions & 0 deletions src/test/ui/liveness/liveness-consts.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/test/ui/liveness/liveness-derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
16 changes: 11 additions & 5 deletions src/test/ui/liveness/liveness-derive.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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