diff options
| author | Aman Arora <me@aman-arora.com> | 2020-11-15 17:09:51 -0500 |
|---|---|---|
| committer | Aman Arora <me@aman-arora.com> | 2020-11-15 17:09:51 -0500 |
| commit | bb8c5e5d8b4961a26f88b320f719249a9db8225e (patch) | |
| tree | edf2da90649c0da6edafa9980f5a8776ee4165e2 | |
| parent | c50e57f946ee5a73b50fa5c52bb7a2a8a0cecf3f (diff) | |
| download | rust-bb8c5e5d8b4961a26f88b320f719249a9db8225e.tar.gz rust-bb8c5e5d8b4961a26f88b320f719249a9db8225e.zip | |
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
| -rw-r--r-- | compiler/rustc_typeck/src/expr_use_visitor.rs | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 83cc1da6985..72e5a7ef1b6 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -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; @@ -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. + 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 @@ -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); @@ -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>( |
