Skip to content
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

RFC-2229: Implement Precise Capture Analysis #78801

Merged
merged 16 commits into from
Nov 17, 2020
Merged
Changes from 1 commit
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
49 changes: 49 additions & 0 deletions compiler/rustc_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rustc_index::vec::Idx;
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::ty::{self, adjustment, TyCtxt};
use rustc_span::Span;
use rustc_target::abi::VariantIdx;

use crate::mem_categorization as mc;
Expand Down Expand Up @@ -570,6 +571,38 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}));
}

/// Walk closure captures but using `closure_caputes` instead
/// of `closure_min_captures`.
///
/// This is needed because clippy uses `ExprUseVisitor` after TypeckResults
/// are written back. We don't currently writeback min_captures to
/// TypeckResults.
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) {
// FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18
// is completed.
debug!("walk_captures_closure_captures({:?}), ", closure_expr);

let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
let cl_span = self.tcx().hir().span(closure_expr.hir_id);

let captures = &self.mc.typeck_results.closure_captures[&closure_def_id];

for (&var_id, &upvar_id) in captures {
let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id);
let captured_place =
return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id));
match upvar_capture {
ty::UpvarCapture::ByValue(_) => {
let mode = copy_or_move(&self.mc, &captured_place);
self.delegate.consume(&captured_place, captured_place.hir_id, mode);
}
ty::UpvarCapture::ByRef(upvar_borrow) => {
self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind);
}
}
}
}

/// Handle the case where the current body contains a closure.
///
/// When the current body being handled is a closure, then we must make sure that
Expand Down Expand Up @@ -625,6 +658,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
PlaceBase::Upvar(upvar_id),
place.projections.clone(),
);

match capture_info.capture_kind {
ty::UpvarCapture::ByValue(_) => {
let mode = copy_or_move(&self.mc, &place_with_id);
Expand All @@ -640,8 +674,23 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
}
} else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) {
// Handle the case where clippy calls ExprUseVisitor after
self.walk_captures_closure_captures(closure_expr)
}
}

fn cat_captured_var(
&mut self,
closure_hir_id: hir::HirId,
closure_span: Span,
var_id: hir::HirId,
) -> mc::McResult<PlaceWithHirId<'tcx>> {
// Create the place for the variable being borrowed, from the
// perspective of the creator (parent) of the closure.
let var_ty = self.mc.node_ty(var_id)?;
self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
}
}

fn copy_or_move<'a, 'tcx>(
Expand Down