1
Fork 0

Replace closures_captures and upvar_capture with closure_min_captures

make changes to liveness to use closure_min_captures

use different span

borrow check uses new structures

rename to CapturedPlace

stop using upvar_capture in regionck

remove the bridge

cleanup from rebase + remove the upvar_capture reference from mutability_errors.rs

remove line from livenes test

make our unused var checking more consistent

update tests

adding more warnings to the tests

move is_ancestor_or_same_capture to rustc_middle/ty

update names to reflect the closures

add FIXME

check that all captures are immutable borrows before returning

add surrounding if statement like the original

move var out of the loop and rename

Co-authored-by: Logan Mosier <logmosier@gmail.com>
Co-authored-by: Roxane Fruytier <roxane.fruytier@hotmail.com>
This commit is contained in:
Jennifer Wills 2020-12-23 15:38:22 -05:00 committed by Aman Arora
parent 1705a7d64b
commit 52dba13e41
14 changed files with 477 additions and 243 deletions

View file

@ -95,7 +95,7 @@ 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, DefIdTree, TyCtxt};
use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
@ -331,7 +331,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
}
}
if let Some(captures) = maps.tcx.typeck(local_def_id).closure_captures.get(&def_id) {
if let Some(captures) = maps.tcx.typeck(local_def_id).closure_min_captures.get(&def_id) {
for &var_hir_id in captures.keys() {
let var_name = maps.tcx.hir().name(var_hir_id);
maps.add_variable(Upvar(var_hir_id, var_name));
@ -408,10 +408,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
if let Some(captures) = self
.tcx
.typeck(closure_def_id)
.closure_captures
.closure_min_captures
.get(&closure_def_id.to_def_id())
{
// If closure captures is Some, upvars_mentioned must also be Some
// If closure_min_captures is Some, upvars_mentioned must also be Some
let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap();
call_caps.extend(captures.keys().map(|var_id| {
let upvar = upvars[var_id];
@ -481,11 +481,10 @@ const ACC_USE: u32 = 4;
struct Liveness<'a, 'tcx> {
ir: &'a mut IrMaps<'tcx>,
body_owner: LocalDefId,
typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
closure_captures: Option<&'tcx FxIndexMap<hir::HirId, ty::UpvarId>>,
closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>,
successors: IndexVec<LiveNode, Option<LiveNode>>,
rwu_table: rwu_table::RWUTable,
@ -509,8 +508,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let typeck_results = ir.tcx.typeck(body_owner);
let param_env = ir.tcx.param_env(body_owner);
let upvars = ir.tcx.upvars_mentioned(body_owner);
let closure_captures = typeck_results.closure_captures.get(&body_owner.to_def_id());
let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner.to_def_id());
let closure_ln = ir.add_live_node(ClosureNode);
let exit_ln = ir.add_live_node(ExitNode);
@ -519,11 +517,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
Liveness {
ir,
body_owner,
typeck_results,
param_env,
upvars,
closure_captures,
closure_min_captures,
successors: IndexVec::from_elem_n(None, num_live_nodes),
rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars),
closure_ln,
@ -707,25 +704,27 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// if they are live on the entry to the closure, since only the closure
// itself can access them on subsequent calls.
if let Some(closure_captures) = self.closure_captures {
if let Some(closure_min_captures) = self.closure_min_captures {
// Mark upvars captured by reference as used after closure exits.
// Since closure_captures is Some, upvars must exists too.
let upvars = self.upvars.unwrap();
for (&var_hir_id, upvar_id) in closure_captures {
let upvar = upvars[&var_hir_id];
match self.typeck_results.upvar_capture(*upvar_id) {
ty::UpvarCapture::ByRef(_) => {
let var = self.variable(var_hir_id, upvar.span);
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
for (&var_hir_id, min_capture_list) in closure_min_captures {
for captured_place in min_capture_list {
match captured_place.info.capture_kind {
ty::UpvarCapture::ByRef(_) => {
let var = self.variable(
var_hir_id,
captured_place.get_capture_kind_span(self.ir.tcx),
);
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
}
ty::UpvarCapture::ByValue(_) => {}
}
ty::UpvarCapture::ByValue(_) => {}
}
}
}
let succ = self.propagate_through_expr(&body.value, self.exit_ln);
if self.closure_captures.is_none() {
if self.closure_min_captures.is_none() {
// Either not a closure, or closure without any captured variables.
// No need to determine liveness of captured variables, since there
// are none.
@ -1221,7 +1220,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
match path.res {
Res::Local(hid) => {
let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid));
let in_captures = self.closure_captures.map_or(false, |c| c.contains_key(&hid));
let in_captures = self.closure_min_captures.map_or(false, |c| c.contains_key(&hid));
match (in_upvars, in_captures) {
(false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span),
@ -1422,52 +1421,52 @@ impl<'tcx> Liveness<'_, 'tcx> {
}
fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
let closure_captures = match self.closure_captures {
let closure_min_captures = match self.closure_min_captures {
None => return,
Some(closure_captures) => closure_captures,
Some(closure_min_captures) => closure_min_captures,
};
// If closure_captures is Some(), upvars must be Some() too.
let upvars = self.upvars.unwrap();
for &var_hir_id in closure_captures.keys() {
let upvar = upvars[&var_hir_id];
let var = self.variable(var_hir_id, upvar.span);
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
closure_expr_id: self.body_owner,
};
match self.typeck_results.upvar_capture(upvar_id) {
ty::UpvarCapture::ByValue(_) => {}
ty::UpvarCapture::ByRef(..) => continue,
};
if self.used_on_entry(entry_ln, var) {
if !self.live_on_entry(entry_ln, var) {
// If closure_min_captures is Some(), upvars must be Some() too.
for (&var_hir_id, min_capture_list) in closure_min_captures {
for captured_place in min_capture_list {
match captured_place.info.capture_kind {
ty::UpvarCapture::ByValue(_) => {}
ty::UpvarCapture::ByRef(..) => continue,
};
let span = captured_place.get_capture_kind_span(self.ir.tcx);
let var = self.variable(var_hir_id, span);
if self.used_on_entry(entry_ln, var) {
if !self.live_on_entry(entry_ln, var) {
if let Some(name) = self.should_warn(var) {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_ASSIGNMENTS,
var_hir_id,
vec![span],
|lint| {
lint.build(&format!(
"value captured by `{}` is never read",
name
))
.help("did you mean to capture by reference instead?")
.emit();
},
);
}
}
} else {
if let Some(name) = self.should_warn(var) {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_ASSIGNMENTS,
lint::builtin::UNUSED_VARIABLES,
var_hir_id,
vec![upvar.span],
vec![span],
|lint| {
lint.build(&format!("value captured by `{}` is never read", name))
lint.build(&format!("unused variable: `{}`", name))
.help("did you mean to capture by reference instead?")
.emit();
},
);
}
}
} else {
if let Some(name) = self.should_warn(var) {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES,
var_hir_id,
vec![upvar.span],
|lint| {
lint.build(&format!("unused variable: `{}`", name))
.help("did you mean to capture by reference instead?")
.emit();
},
);
}
}
}
}