Skip to content

Commit 74fcbfb

Browse files
committed
liveness: Include upvars in the analysis
1 parent 7c63014 commit 74fcbfb

File tree

1 file changed

+33
-36
lines changed

1 file changed

+33
-36
lines changed

src/librustc_passes/liveness.rs

+33-36
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ struct LocalInfo {
244244
enum VarKind {
245245
Param(HirId, Symbol),
246246
Local(LocalInfo),
247+
Upvar(HirId, Symbol),
247248
}
248249

249250
struct IrMaps<'tcx> {
@@ -296,7 +297,7 @@ impl IrMaps<'tcx> {
296297
self.num_vars += 1;
297298

298299
match vk {
299-
Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => {
300+
Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => {
300301
self.variable_map.insert(node_id, v);
301302
}
302303
}
@@ -317,14 +318,14 @@ impl IrMaps<'tcx> {
317318

318319
fn variable_name(&self, var: Variable) -> String {
319320
match self.var_kinds[var.get()] {
320-
Local(LocalInfo { name, .. }) | Param(_, name) => name.to_string(),
321+
Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name.to_string(),
321322
}
322323
}
323324

324325
fn variable_is_shorthand(&self, var: Variable) -> bool {
325326
match self.var_kinds[var.get()] {
326327
Local(LocalInfo { is_shorthand, .. }) => is_shorthand,
327-
Param(..) => false,
328+
Param(..) | Upvar(..) => false,
328329
}
329330
}
330331

@@ -365,6 +366,14 @@ fn visit_fn<'tcx>(
365366

366367
let body = ir.tcx.hir().body(body_id);
367368

369+
if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) {
370+
for (&var_hir_id, _upvar) in upvars {
371+
debug!("adding upvar {:?}", var_hir_id);
372+
let var_name = ir.tcx.hir().name(var_hir_id);
373+
fn_maps.add_variable(Upvar(var_hir_id, var_name));
374+
}
375+
}
376+
368377
for param in body.params {
369378
let is_shorthand = match param.pat.kind {
370379
rustc_hir::PatKind::Struct(..) => true,
@@ -450,11 +459,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
450459
// live nodes required for uses or definitions of variables:
451460
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
452461
debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
453-
if let Res::Local(var_hir_id) = path.res {
454-
let upvars = ir.tcx.upvars_mentioned(ir.body_owner);
455-
if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) {
456-
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
457-
}
462+
if let Res::Local(_var_hir_id) = path.res {
463+
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
458464
}
459465
intravisit::walk_expr(ir, expr);
460466
}
@@ -470,16 +476,9 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
470476
let mut call_caps = Vec::new();
471477
let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id);
472478
if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) {
473-
let parent_upvars = ir.tcx.upvars_mentioned(ir.body_owner);
474-
call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| {
475-
let has_parent =
476-
parent_upvars.map_or(false, |upvars| upvars.contains_key(&var_id));
477-
if !has_parent {
478-
let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
479-
Some(CaptureInfo { ln: upvar_ln, var_hid: var_id })
480-
} else {
481-
None
482-
}
479+
call_caps.extend(upvars.iter().map(|(&var_id, upvar)| {
480+
let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
481+
CaptureInfo { ln: upvar_ln, var_hid: var_id }
483482
}));
484483
}
485484
ir.set_captures(expr.hir_id, call_caps);
@@ -894,6 +893,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
894893
debug!("compute: using id for body, {:?}", body);
895894

896895
let s = self.s;
896+
897+
if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) {
898+
for (&var_hir_id, upvar) in upvars.iter().rev() {
899+
let var = self.variable(var_hir_id, upvar.span);
900+
self.acc(s.exit_ln, var, ACC_READ | ACC_USE);
901+
}
902+
}
903+
897904
let entry_ln = self.propagate_through_expr(body, s.exit_ln);
898905

899906
// hack to skip the loop unless debug! is enabled:
@@ -1345,14 +1352,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
13451352
acc: u32,
13461353
) -> LiveNode {
13471354
match path.res {
1348-
Res::Local(hid) => {
1349-
let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner);
1350-
if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) {
1351-
self.access_var(hir_id, hid, succ, acc, path.span)
1352-
} else {
1353-
succ
1354-
}
1355-
}
1355+
Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span),
13561356
_ => succ,
13571357
}
13581358
}
@@ -1511,16 +1511,13 @@ impl<'tcx> Liveness<'_, 'tcx> {
15111511
match expr.kind {
15121512
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
15131513
if let Res::Local(var_hid) = path.res {
1514-
let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner);
1515-
if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) {
1516-
// Assignment to an immutable variable or argument: only legal
1517-
// if there is no later assignment. If this local is actually
1518-
// mutable, then check for a reassignment to flag the mutability
1519-
// as being used.
1520-
let ln = self.live_node(expr.hir_id, expr.span);
1521-
let var = self.variable(var_hid, expr.span);
1522-
self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
1523-
}
1514+
// Assignment to an immutable variable or argument: only legal
1515+
// if there is no later assignment. If this local is actually
1516+
// mutable, then check for a reassignment to flag the mutability
1517+
// as being used.
1518+
let ln = self.live_node(expr.hir_id, expr.span);
1519+
let var = self.variable(var_hid, expr.span);
1520+
self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
15241521
}
15251522
}
15261523
_ => {

0 commit comments

Comments
 (0)