about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAman Arora <me@aman-arora.com>2020-11-15 17:09:51 -0500
committerAman Arora <me@aman-arora.com>2020-11-15 17:09:51 -0500
commitbb8c5e5d8b4961a26f88b320f719249a9db8225e (patch)
treeedf2da90649c0da6edafa9980f5a8776ee4165e2
parentc50e57f946ee5a73b50fa5c52bb7a2a8a0cecf3f (diff)
downloadrust-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.rs49
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>(