Skip to content

Commit bb8c5e5

Browse files
committed
Fix case when ExprUseVisitor is called after typeck writeback
Clippy uses `ExprUseVisitor` and atleast in some cases it runs after writeback. We currently don't writeback the min_capture results of closure capture analysis since no place within the compiler itself uses it. In the short term to fix clippy we add a fallback when walking captures of a closure to check if closure_capture analysis has any entries in it. Writeback for closure_min_captures will be implemented in rust-lang/project-rfc-2229#18
1 parent c50e57f commit bb8c5e5

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

compiler/rustc_typeck/src/expr_use_visitor.rs

+49
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_index::vec::Idx;
1515
use rustc_infer::infer::InferCtxt;
1616
use rustc_middle::hir::place::ProjectionKind;
1717
use rustc_middle::ty::{self, adjustment, TyCtxt};
18+
use rustc_span::Span;
1819
use rustc_target::abi::VariantIdx;
1920

2021
use crate::mem_categorization as mc;
@@ -570,6 +571,38 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
570571
}));
571572
}
572573

574+
/// Walk closure captures but using `closure_caputes` instead
575+
/// of `closure_min_captures`.
576+
///
577+
/// This is needed because clippy uses `ExprUseVisitor` after TypeckResults
578+
/// are written back. We don't currently writeback min_captures to
579+
/// TypeckResults.
580+
fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) {
581+
// FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18
582+
// is completed.
583+
debug!("walk_captures_closure_captures({:?}), ", closure_expr);
584+
585+
let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
586+
let cl_span = self.tcx().hir().span(closure_expr.hir_id);
587+
588+
let captures = &self.mc.typeck_results.closure_captures[&closure_def_id];
589+
590+
for (&var_id, &upvar_id) in captures {
591+
let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id);
592+
let captured_place =
593+
return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id));
594+
match upvar_capture {
595+
ty::UpvarCapture::ByValue(_) => {
596+
let mode = copy_or_move(&self.mc, &captured_place);
597+
self.delegate.consume(&captured_place, captured_place.hir_id, mode);
598+
}
599+
ty::UpvarCapture::ByRef(upvar_borrow) => {
600+
self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind);
601+
}
602+
}
603+
}
604+
}
605+
573606
/// Handle the case where the current body contains a closure.
574607
///
575608
/// When the current body being handled is a closure, then we must make sure that
@@ -625,6 +658,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
625658
PlaceBase::Upvar(upvar_id),
626659
place.projections.clone(),
627660
);
661+
628662
match capture_info.capture_kind {
629663
ty::UpvarCapture::ByValue(_) => {
630664
let mode = copy_or_move(&self.mc, &place_with_id);
@@ -640,8 +674,23 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
640674
}
641675
}
642676
}
677+
} else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) {
678+
// Handle the case where clippy calls ExprUseVisitor after
679+
self.walk_captures_closure_captures(closure_expr)
643680
}
644681
}
682+
683+
fn cat_captured_var(
684+
&mut self,
685+
closure_hir_id: hir::HirId,
686+
closure_span: Span,
687+
var_id: hir::HirId,
688+
) -> mc::McResult<PlaceWithHirId<'tcx>> {
689+
// Create the place for the variable being borrowed, from the
690+
// perspective of the creator (parent) of the closure.
691+
let var_ty = self.mc.node_ty(var_id)?;
692+
self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
693+
}
645694
}
646695

647696
fn copy_or_move<'a, 'tcx>(

0 commit comments

Comments
 (0)