]> git.lizzy.rs Git - rust.git/commitdiff
Fix case when ExprUseVisitor is called after typeck writeback
authorAman Arora <me@aman-arora.com>
Sun, 15 Nov 2020 22:09:51 +0000 (17:09 -0500)
committerAman Arora <me@aman-arora.com>
Sun, 15 Nov 2020 22:09:51 +0000 (17:09 -0500)
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

compiler/rustc_typeck/src/expr_use_visitor.rs

index 83cc1da69851f428bba762e50b4af3aaa1657ef4..72e5a7ef1b6e14ba667935240c0619862d358d03 100644 (file)
@@ -15,6 +15,7 @@
 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 @@ fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
         }));
     }
 
+    /// 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 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
                         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 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
                     }
                 }
             }
+        } 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>(