about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/context.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs28
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs58
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs31
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs26
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs13
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs8
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs96
-rw-r--r--src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs84
-rw-r--r--src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr72
-rw-r--r--src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs139
-rw-r--r--src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr212
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs (renamed from src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs)7
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr (renamed from src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr)2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs5
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr8
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr (renamed from src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr)2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs7
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs25
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr11
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr25
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs2
32 files changed, 788 insertions, 136 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 425e62d6f61..00c03d75380 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -431,7 +431,29 @@ pub struct TypeckResults<'tcx> {
     /// see `MinCaptureInformationMap` for more details.
     pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
 
-    pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause)>>,
+    /// Tracks the fake reads required for a closure and the reason for the fake read.
+    /// When performing pattern matching for closures, there are times we don't end up
+    /// reading places that are mentioned in a closure (because of _ patterns). However,
+    /// to ensure the places are initialized, we introduce fake reads.
+    /// Consider these two examples:
+    /// ``` (discriminant matching with only wildcard arm)
+    /// let x: u8;
+    /// let c = || match x { _ => () };
+    /// ```
+    /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
+    /// want to capture it. However, we do still want an error here, because `x` should have
+    /// to be initialized at the point where c is created. Therefore, we add a "fake read"
+    /// instead.
+    /// ``` (destructured assignments)
+    /// let c = || {
+    ///     let (t1, t2) = t;
+    /// }
+    /// ```
+    /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
+    /// we never capture `t`. This becomes an issue when we build MIR as we require
+    /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
+    /// issue by fake reading `t`.
+    pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
 
     /// Stores the type, expression, span and optional scope span of all types
     /// that are live across the yield of this generator (if a generator).
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 0e70cd36efb..fbc9c30fe53 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -90,15 +90,13 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
         let hir_projection = match mir_projection {
             ProjectionElem::Deref => HirProjectionKind::Deref,
             ProjectionElem::Field(field, _) => {
-                // We will never encouter this for multivariant enums,
-                // read the comment for `Downcast`.
                 let variant = variant.unwrap_or(VariantIdx::new(0));
                 HirProjectionKind::Field(field.index() as u32, variant)
             }
             ProjectionElem::Downcast(.., idx) => {
-                // This projections exist for enums that have
-                // single and multiple variants.
-                // For single variants, enums are not captured completely.
+                // We don't expect to see multi-variant enums here, as earlier
+                // phases will have truncated them already. However, there can
+                // still be downcasts, thanks to single-variant enums.
                 // We keep track of VariantIdx so we can use this information
                 // if the next ProjectionElem is a Field.
                 variant = Some(*idx);
@@ -200,7 +198,7 @@ fn find_capture_matching_projections<'a, 'tcx>(
 /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
 /// `PlaceBuilder` now starts from `PlaceBase::Local`.
 ///
-/// Returns a Result with the error being the HirId of the Upvar that was not found.
+/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
 fn to_upvars_resolved_place_builder<'a, 'tcx>(
     from_builder: PlaceBuilder<'tcx>,
     tcx: TyCtxt<'tcx>,
@@ -305,15 +303,23 @@ impl<'tcx> PlaceBuilder<'tcx> {
         to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
     }
 
+    /// Attempts to resolve the `PlaceBuilder`.
+    /// On success, it will return the resolved `PlaceBuilder`.
+    /// On failure, it will return itself.
+    ///
+    /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
+    /// resolve a disjoint field whose root variable is not captured
+    /// (destructured assignments) or when attempting to resolve a root
+    /// variable (discriminant matching with only wildcard arm) that is
+    /// not captured. This can happen because the final mir that will be
+    /// generated doesn't require a read for this place. Failures will only
+    /// happen inside closures.
     crate fn try_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
     ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
-        match to_upvars_resolved_place_builder(self, tcx, typeck_results) {
-            Ok(upvars_resolved) => Ok(upvars_resolved),
-            Err(upvars_unresolved) => Err(upvars_unresolved),
-        }
+        to_upvars_resolved_place_builder(self, tcx, typeck_results)
     }
 
     crate fn base(&self) -> PlaceBase {
@@ -662,7 +668,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             block,
             source_info,
             len,
-            Rvalue::Len(slice.clone().into_place(self.tcx, self.typeck_results)),
+            Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
         );
         // lt = idx < len
         self.cfg.push_assign(
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index c7f16fd4e40..53c87d71e13 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -165,13 +165,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
-            ExprKind::Closure {
-                closure_id,
-                substs,
-                upvars,
-                movability,
-                fake_reads: opt_fake_reads,
-            } => {
+            ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => {
+                // Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
+                // and push the fake reads.
+                // This must come before creating the operands. This is required in case
+                // there is a fake read and a borrow of the same path, since otherwise the
+                // fake read might interfere with the borrow. Consider an example like this
+                // one:
+                // ```
+                // let mut x = 0;
+                // let c = || {
+                //     &mut x; // mutable borrow of `x`
+                //     match x { _ => () } // fake read of `x`
+                // };
+                // ```
+
+                // FIXME(RFC2229): Remove feature gate once diagnostics are improved
+                if this.tcx.features().capture_disjoint_fields {
+                    for (thir_place, cause, hir_id) in fake_reads.into_iter() {
+                        let place_builder =
+                            unpack!(block = this.as_place_builder(block, thir_place));
+
+                        if let Ok(place_builder_resolved) =
+                            place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
+                        {
+                            let mir_place =
+                                place_builder_resolved.into_place(this.tcx, this.typeck_results);
+                            this.cfg.push_fake_read(
+                                block,
+                                this.source_info(this.tcx.hir().span(hir_id)),
+                                cause,
+                                mir_place,
+                            );
+                        }
+                    }
+                }
+
                 // see (*) above
                 let operands: Vec<_> = upvars
                     .into_iter()
@@ -210,21 +239,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         }
                     })
                     .collect();
-                if let Some(fake_reads) = opt_fake_reads {
-                    for (thir_place, cause) in fake_reads.into_iter() {
-                        let place_builder =
-                            unpack!(block = this.as_place_builder(block, thir_place));
-
-                        if let Ok(place_builder_resolved) =
-                            place_builder.clone().try_upvars_resolved(this.tcx, this.typeck_results)
-                        {
-                            let mir_place = place_builder_resolved
-                                .clone()
-                                .into_place(this.tcx, this.typeck_results);
-                            this.cfg.push_fake_read(block, source_info, cause, mir_place);
-                        }
-                    }
-                }
 
                 let result = match substs {
                     UpvarSubsts::Generator(substs) => {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 59b3fd86478..6e8b25c9162 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -146,8 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if let Ok(scrutinee_builder) =
             scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
         {
-            let scrutinee_place =
-                scrutinee_builder.clone().into_place(self.tcx, self.typeck_results);
+            let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
             self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
         }
 
@@ -245,7 +244,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let arm_source_info = self.source_info(arm.span);
                 let arm_scope = (arm.scope, arm_source_info);
                 self.in_scope(arm_scope, arm.lint_level, |this| {
-                    let body = arm.body.clone();
+                    let body = arm.body;
+
+                    // `try_upvars_resolved` may fail if it is unable to resolve the given
+                    // `PlaceBuilder` inside a closure. In this case, we don't want to include
+                    // a scrutinee place. `scrutinee_place_builder` will fail to be resolved
+                    // if the only match arm is a wildcard (`_`).
+                    // Example:
+                    // ```
+                    // let foo = (0, 1);
+                    // let c = || {
+                    //    match foo { _ => () };
+                    // };
+                    // ```
                     let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
                     let scrutinee_place: Place<'tcx>;
                     if let Ok(scrutinee_builder) = scrutinee_place_builder
@@ -496,6 +507,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
                     )))) = self.local_decls[local].local_info
                     {
+                        // `try_upvars_resolved` may fail if it is unable to resolve the given
+                        // `PlaceBuilder` inside a closure. In this case, we don't want to include
+                        // a scrutinee place. `scrutinee_place_builder` will fail for destructured
+                        // assignments. This is because a closure only captures the precise places
+                        // that it will read and as a result a closure may not capture the entire
+                        // tuple/struct and rather have individual places that will be read in the
+                        // final MIR.
+                        // Example:
+                        // ```
+                        // let foo = (0, 1);
+                        // let c = || {
+                        //    let (v1, v2) = foo;
+                        // };
+                        // ```
                         if let Ok(match_pair_resolved) =
                             initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
                         {
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 02f1998f496..b13a0ef8201 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if let Ok(test_place_builder) =
             place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
         {
-            place = test_place_builder.clone().into_place(self.tcx, self.typeck_results);
+            place = test_place_builder.into_place(self.tcx, self.typeck_results);
         } else {
             return;
         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index dee69793f2a..2f58f2975b1 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -454,20 +454,20 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)),
                 );
 
+                // Convert the closure fake reads, if any, from hir `Place` to ExprRef
                 let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
-                    Some(vals) => Some(
-                        vals.iter()
-                            .map(|(place, cause)| {
-                                (
-                                    self.arena.alloc(
-                                        self.convert_captured_hir_place(expr, place.clone()),
-                                    ),
-                                    *cause,
-                                )
-                            })
-                            .collect(),
-                    ),
-                    None => None,
+                    Some(fake_reads) => fake_reads
+                        .iter()
+                        .map(|(place, cause, hir_id)| {
+                            (
+                                self.arena
+                                    .alloc(self.convert_captured_hir_place(expr, place.clone())),
+                                *cause,
+                                *hir_id,
+                            )
+                        })
+                        .collect(),
+                    None => Vec::new(),
                 };
 
                 ExprKind::Closure {
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index a6ec3b7bdd2..71d3093854d 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -281,7 +281,7 @@ pub enum ExprKind<'thir, 'tcx> {
         substs: UpvarSubsts<'tcx>,
         upvars: &'thir [Expr<'thir, 'tcx>],
         movability: Option<hir::Movability>,
-        fake_reads: Option<Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause)>>,
+        fake_reads: Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause, hir::HirId)>,
     },
     Literal {
         literal: &'tcx Const<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 9a43eaa3f5d..e79349796d2 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -248,8 +248,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
         self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
-        let fake_reads =
-            delegate.fake_reads.into_iter().map(|(place, cause)| (place, cause)).collect();
+        let fake_reads = delegate
+            .fake_reads
+            .into_iter()
+            .map(|(place, cause, hir_id)| (place, cause, hir_id))
+            .collect();
         self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
 
         // If we are also inferred the closure kind here,
@@ -1154,7 +1157,7 @@ struct InferBorrowKind<'a, 'tcx> {
     /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
     /// ```
     capture_information: InferredCaptureInformation<'tcx>,
-    fake_reads: Vec<(Place<'tcx>, FakeReadCause)>,
+    fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
 }
 
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@@ -1416,9 +1419,9 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
-    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause) {
+    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
         if let PlaceBase::Upvar(_) = place.base {
-            self.fake_reads.push((place, cause));
+            self.fake_reads.push((place, cause, diag_expr_id));
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 1be629ce9dc..b88a96de698 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -371,18 +371,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     fn visit_fake_reads_map(&mut self) {
         let mut resolved_closure_fake_reads: FxHashMap<
             DefId,
-            Vec<(HirPlace<'tcx>, FakeReadCause)>,
+            Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>,
         > = Default::default();
         for (closure_def_id, fake_reads) in
             self.fcx.typeck_results.borrow().closure_fake_reads.iter()
         {
-            let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause)>::new();
-            for (place, cause) in fake_reads.iter() {
+            let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>::new();
+            for (place, cause, hir_id) in fake_reads.iter() {
                 let locatable =
                     self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
 
                 let resolved_fake_read = self.resolve(place.clone(), &locatable);
-                resolved_fake_reads.push((resolved_fake_read, *cause));
+                resolved_fake_reads.push((resolved_fake_read, *cause, *hir_id));
             }
             resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads);
         }
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 0172f993c26..dced4aac049 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -7,11 +7,11 @@ pub use self::ConsumeMode::*;
 // Export these here so that Clippy can use them.
 pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
 
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::PatKind;
-//use rustc_hir::QPath;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::ProjectionKind;
@@ -54,7 +54,8 @@ pub trait Delegate<'tcx> {
     // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
 
-    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause);
+    // The `place` should be a fake read because of specified `cause`.
+    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -241,20 +242,33 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
                 let mut needs_to_be_read = false;
                 for arm in arms.iter() {
-                    return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| {
+                    return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| {
                         match &pat.kind {
-                            PatKind::Binding(_, _, _, opt_sub_pat) => {
+                            PatKind::Binding(.., opt_sub_pat) => {
                                 // If the opt_sub_pat is None, than the binding does not count as
-                                // a wildcard for the purpose of borrowing discr
-                                if let None = opt_sub_pat {
+                                // a wildcard for the purpose of borrowing discr.
+                                if opt_sub_pat.is_none() {
                                     needs_to_be_read = true;
                                 }
                             }
-                            PatKind::TupleStruct(_, _, _)
-                            | PatKind::Struct(_, _, _)
-                            | PatKind::Lit(_) => {
-                                // If the PatKind is a TupleStruct, Struct, or Lit then we want
-                                // to borrow discr
+                            PatKind::TupleStruct(..)
+                            | PatKind::Path(..)
+                            | PatKind::Struct(..)
+                            | PatKind::Tuple(..) => {
+                                // If the PatKind is a TupleStruct, Struct or Tuple then we want to check
+                                // whether the Variant is a MultiVariant or a SingleVariant. We only want
+                                // to borrow discr if it is a MultiVariant.
+                                // If it is a SingleVariant and creates a binding we will handle that when
+                                // this callback gets called again.
+                                if let ty::Adt(def, _) = place.place.base_ty.kind() {
+                                    if def.variants.len() > 1 {
+                                        needs_to_be_read = true;
+                                    }
+                                }
+                            }
+                            PatKind::Lit(_) => {
+                                // If the PatKind is a Lit then we want
+                                // to borrow discr.
                                 needs_to_be_read = true;
                             }
                             _ => {}
@@ -264,6 +278,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
                 if needs_to_be_read {
                     self.borrow_expr(&discr, ty::ImmBorrow);
+                } else {
+                    self.delegate.fake_read(
+                        discr_place.place.clone(),
+                        FakeReadCause::ForMatchedPlace,
+                        discr_place.hir_id,
+                    );
+
+                    // We always want to walk the discriminant. We want to make sure, for instance,
+                    // that the discriminant has been initialized.
+                    self.walk_expr(&discr);
                 }
 
                 // treatment of the discriminant is handled while walking the arms.
@@ -553,7 +577,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     }
 
     fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
-        self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForMatchedPlace);
+        self.delegate.fake_read(
+            discr_place.place.clone(),
+            FakeReadCause::ForMatchedPlace,
+            discr_place.hir_id,
+        );
         self.walk_pat(discr_place, &arm.pat);
 
         if let Some(hir::Guard::If(ref e)) = arm.guard {
@@ -566,7 +594,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
     /// let binding, and *not* a match arm or nested pat.)
     fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
-        self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForLet);
+        self.delegate.fake_read(
+            discr_place.place.clone(),
+            FakeReadCause::ForLet,
+            discr_place.hir_id,
+        );
         self.walk_pat(discr_place, pat);
     }
 
@@ -634,6 +666,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
     /// closure as the DefId.
     fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
+        fn upvar_is_local_variable(
+            upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
+            upvar_id: &hir::HirId,
+            body_owner_is_closure: bool,
+        ) -> bool {
+            upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure)
+        }
+
         debug!("walk_captures({:?})", closure_expr);
 
         let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
@@ -645,16 +685,32 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             ty::Closure(..) | ty::Generator(..)
         );
 
+        // If we have a nested closure, we want to include the fake reads present in the nested closure.
         if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
-            for (fake_read, cause) in fake_reads.iter() {
+            for (fake_read, cause, hir_id) in fake_reads.iter() {
                 match fake_read.base {
                     PlaceBase::Upvar(upvar_id) => {
-                        if upvars.map_or(body_owner_is_closure, |upvars| {
-                            !upvars.contains_key(&upvar_id.var_path.hir_id)
-                        }) {
+                        if upvar_is_local_variable(
+                            upvars,
+                            &upvar_id.var_path.hir_id,
+                            body_owner_is_closure,
+                        ) {
                             // The nested closure might be fake reading the current (enclosing) closure's local variables.
-                            // We check if the root variable is ever mentioned within the enclosing closure, if not
-                            // then for the current body (if it's a closure) these do not require fake_read, we will ignore them.
+                            // The only places we want to fake read before creating the parent closure are the ones that
+                            // are not local to it/ defined by it.
+                            //
+                            // ```rust,ignore(cannot-test-this-because-pseduo-code)
+                            // let v1 = (0, 1);
+                            // let c = || { // fake reads: v1
+                            //    let v2 = (0, 1);
+                            //    let e = || { // fake reads: v1, v2
+                            //       let (_, t1) = v1;
+                            //       let (_, t2) = v2;
+                            //    }
+                            // }
+                            // ```
+                            // This check is performed when visiting the body of the outermost closure (`c`) and ensures
+                            // that we don't add a fake read of v2 in c.
                             continue;
                         }
                     }
@@ -665,7 +721,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         );
                     }
                 };
-                self.delegate.fake_read(fake_read.clone(), *cause);
+                self.delegate.fake_read(fake_read.clone(), *cause, *hir_id);
             }
         }
 
diff --git a/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs
new file mode 100644
index 00000000000..609a11a578a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs
@@ -0,0 +1,84 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(never_type)]
+
+// Should fake read the discriminant and throw an error
+fn test1() {
+    let x: !;
+    let c1 = || match x { };
+    //~^ ERROR: use of possibly-uninitialized variable: `x`
+}
+
+// Should fake read the discriminant and throw an error
+fn test2() {
+    let x: !;
+    let c2 = || match x { _ => () };
+    //~^ ERROR: borrow of possibly-uninitialized variable: `x`
+}
+
+// Testing single variant patterns
+enum SingleVariant {
+    Points(u32)
+}
+
+// Should fake read the discriminant and throw an error
+fn test3() {
+    let variant: !;
+    let c = || {
+    //~^ ERROR: borrow of possibly-uninitialized variable: `variant`
+        match variant {
+            SingleVariant::Points(_) => {}
+        }
+    };
+    c();
+}
+
+// Should fake read the discriminant and throw an error
+fn test4() {
+    let variant: !;
+    let c = || {
+    //~^ ERROR: borrow of possibly-uninitialized variable: `variant`
+        match variant {
+            SingleVariant::Points(a) => {
+                println!("{:?}", a);
+            }
+        }
+    };
+    c();
+}
+
+fn test5() {
+    let t: !;
+    let g: !;
+
+    let a = || {
+        match g { };
+        //~^ ERROR: use of possibly-uninitialized variable: `g`
+        let c = ||  {
+            match t { };
+            //~^ ERROR: use of possibly-uninitialized variable: `t`
+        };
+
+        c();
+    };
+
+}
+
+// Should fake read the discriminant and throw an error
+fn test6() {
+    let x: u8;
+    let c1 = || match x { };
+    //~^ ERROR: use of possibly-uninitialized variable: `x`
+    //~| ERROR: non-exhaustive patterns: type `u8` is non-empty
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+    test4();
+    test5();
+    test6();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr
new file mode 100644
index 00000000000..c225abb58b7
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr
@@ -0,0 +1,72 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/pattern-matching-should-fail.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/pattern-matching-should-fail.rs:72:23
+   |
+LL |     let c1 = || match x { };
+   |                       ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+  --> $DIR/pattern-matching-should-fail.rs:10:23
+   |
+LL |     let c1 = || match x { };
+   |                       ^ use of possibly-uninitialized `x`
+
+error[E0381]: borrow of possibly-uninitialized variable: `x`
+  --> $DIR/pattern-matching-should-fail.rs:17:14
+   |
+LL |     let c2 = || match x { _ => () };
+   |              ^^       - borrow occurs due to use in closure
+   |              |
+   |              use of possibly-uninitialized `x`
+
+error[E0381]: borrow of possibly-uninitialized variable: `variant`
+  --> $DIR/pattern-matching-should-fail.rs:29:13
+   |
+LL |     let c = || {
+   |             ^^ use of possibly-uninitialized `variant`
+LL |
+LL |         match variant {
+   |               ------- borrow occurs due to use in closure
+
+error[E0381]: borrow of possibly-uninitialized variable: `variant`
+  --> $DIR/pattern-matching-should-fail.rs:41:13
+   |
+LL |     let c = || {
+   |             ^^ use of possibly-uninitialized `variant`
+LL |
+LL |         match variant {
+   |               ------- borrow occurs due to use in closure
+
+error[E0381]: use of possibly-uninitialized variable: `g`
+  --> $DIR/pattern-matching-should-fail.rs:57:15
+   |
+LL |         match g { };
+   |               ^ use of possibly-uninitialized `g`
+
+error[E0381]: use of possibly-uninitialized variable: `t`
+  --> $DIR/pattern-matching-should-fail.rs:60:19
+   |
+LL |             match t { };
+   |                   ^ use of possibly-uninitialized `t`
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+  --> $DIR/pattern-matching-should-fail.rs:72:23
+   |
+LL |     let c1 = || match x { };
+   |                       ^ use of possibly-uninitialized `x`
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0004, E0381.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs
new file mode 100644
index 00000000000..0a877dd366c
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs
@@ -0,0 +1,139 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+// Should capture the discriminant since a variant of a multivariant enum is
+// mentioned in the match arm; the discriminant is captured by the closure regardless
+// of if it creates a binding
+fn test_1_should_capture() {
+    let variant = Some(2229);
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match variant {
+        //~^ NOTE: Capturing variant[] -> ImmBorrow
+        //~| NOTE: Min Capture variant[] -> ImmBorrow
+            Some(_) => {}
+            _ => {}
+        }
+    };
+    c();
+}
+
+// Should not capture the discriminant since only a wildcard is mentioned in the
+// match arm
+fn test_2_should_not_capture() {
+    let variant = Some(2229);
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+        match variant {
+            _ => {}
+        }
+    };
+    c();
+}
+
+// Testing single variant patterns
+enum SingleVariant {
+    Points(u32)
+}
+
+// Should not capture the discriminant since the single variant mentioned
+// in the match arm does not trigger a binding
+fn test_3_should_not_capture_single_variant() {
+    let variant = SingleVariant::Points(1);
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+        match variant {
+            SingleVariant::Points(_) => {}
+        }
+    };
+    c();
+}
+
+// Should not capture the discriminant since the single variant mentioned
+// in the match arm does not trigger a binding
+fn test_6_should_capture_single_variant() {
+    let variant = SingleVariant::Points(1);
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match variant {
+            //~^ NOTE: Capturing variant[] -> ImmBorrow
+            //~| NOTE: Capturing variant[(0, 0)] -> ImmBorrow
+            //~| NOTE: Min Capture variant[] -> ImmBorrow
+            SingleVariant::Points(a) => {
+                println!("{:?}", a);
+            }
+        }
+    };
+    c();
+}
+
+// Should not capture the discriminant since only wildcards are mentioned in the
+// match arm
+fn test_4_should_not_capture_array() {
+    let array: [i32; 3] = [0; 3];
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+        match array {
+            [_,_,_] => {}
+        }
+    };
+    c();
+}
+
+// Testing MultiVariant patterns
+enum MVariant {
+    A,
+    B,
+    C,
+}
+
+// Should capture the discriminant since a variant of the multi variant enum is
+// mentioned in the match arm; the discriminant is captured by the closure
+// regardless of if it creates a binding
+fn test_5_should_capture_multi_variant() {
+    let variant = MVariant::A;
+    let c =  #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match variant {
+        //~^ NOTE: Capturing variant[] -> ImmBorrow
+        //~| NOTE: Min Capture variant[] -> ImmBorrow
+            MVariant::A => {}
+            _ => {}
+        }
+    };
+    c();
+}
+
+fn main() {
+    test_1_should_capture();
+    test_2_should_not_capture();
+    test_3_should_not_capture_single_variant();
+    test_6_should_capture_single_variant();
+    test_4_should_not_capture_array();
+    test_5_should_capture_multi_variant();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr
new file mode 100644
index 00000000000..ad3e96a5753
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr
@@ -0,0 +1,212 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:12:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:33:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:54:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:70:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:92:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/patterns-capture-analysis.rs:116:14
+   |
+LL |     let c =  #[rustc_capture_analysis]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/patterns-capture-analysis.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:16:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:19:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:16:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:19:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:36:5
+   |
+LL | /     || {
+LL | |
+LL | |         match variant {
+LL | |             _ => {}
+LL | |         }
+LL | |     };
+   | |_____^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:57:5
+   |
+LL | /     || {
+LL | |
+LL | |         match variant {
+LL | |             SingleVariant::Points(_) => {}
+LL | |         }
+LL | |     };
+   | |_____^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:73:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:76:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+note: Capturing variant[(0, 0)] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:76:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:73:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:76:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:95:5
+   |
+LL | /     || {
+LL | |
+LL | |         match array {
+LL | |             [_,_,_] => {}
+LL | |         }
+LL | |     };
+   | |_____^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:119:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:122:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:119:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match variant {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture variant[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:122:15
+   |
+LL |         match variant {
+   |               ^^^^^^^
+
+error: aborting due to 15 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs
index 6b3835634c6..eaea0dbfb5e 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs
@@ -3,20 +3,23 @@
 //~^ WARNING: the feature `capture_disjoint_fields` is incomplete
 
 fn test1() {
-    let foo = [1, 2, 3];
+    let foo : [Vec<u8>; 3] = ["String".into(), "String".into(), "String".into()];
     let c = || {
         match foo { _ => () };
     };
+    drop(foo);
+    c();
 }
 
 fn test2() {
-    let foo = Some([1, 2, 3]);
+    let foo : Option<[Vec<u8>; 3]> = Some(["String".into(), "String".into(), "String".into()]);
     let c = || {
         match foo {
             Some(_) => 1,
             _ => 2
         };
     };
+    c();
 }
 
 fn main() {
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr
index 6f5b28aa6cf..2c17a189afb 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr
@@ -1,5 +1,5 @@
 warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/no_capture_with_wildcard_match.rs:2:12
+  --> $DIR/capture_with_wildcard_match.rs:2:12
    |
 LL | #![feature(capture_disjoint_fields)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs
index d91a28feae5..3ad083a92d5 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs
@@ -4,7 +4,6 @@
 #![warn(unused)]
 
 fn main() {
-    let _z = 9;
     let t = (String::from("Hello"), String::from("World"));
     let g = (String::from("Mr"), String::from("Goose"));
 
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr
index d88c16567b7..c4abf934123 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr
@@ -8,7 +8,7 @@ LL | #![feature(capture_disjoint_fields)]
    = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
 
 warning: unused variable: `t2`
-  --> $DIR/destructure-pattern-closure-within-closure.rs:15:21
+  --> $DIR/destructure-pattern-closure-within-closure.rs:14:21
    |
 LL |             let (_, t2) = t;
    |                     ^^ help: if this is intentional, prefix it with an underscore: `_t2`
@@ -21,7 +21,7 @@ LL | #![warn(unused)]
    = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
 
 warning: unused variable: `g2`
-  --> $DIR/destructure-pattern-closure-within-closure.rs:12:17
+  --> $DIR/destructure-pattern-closure-within-closure.rs:11:17
    |
 LL |         let (_, g2) = g;
    |                 ^^ help: if this is intentional, prefix it with an underscore: `_g2`
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs
index 7d2c573dddd..65527648b2c 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs
@@ -80,7 +80,6 @@ fn test7() {
     };
 }
 
-// [FIXME] RFC2229 Add an explanation for test
 fn test8() {
     let x = 0;
     //~^ WARN unused variable: `x`
@@ -90,10 +89,10 @@ fn test8() {
 
     let c = || {
         let _ = x;
-        let Point { x, y } = p; // 1
+        let Point { x, y } = p;
         //~^ WARN unused variable: `x`
         println!("{}", y);
-        let (_, _) = tup; // 2
+        let (_, _) = tup;
     };
 
     c();
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr
index b92bf089e9e..fcfe9ee95f1 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr
@@ -45,19 +45,19 @@ LL |     let t = (String::from("Hello"), String::from("World"));
    |         ^ help: if this is intentional, prefix it with an underscore: `_t`
 
 warning: unused variable: `x`
-  --> $DIR/destructure_patterns.rs:93:21
+  --> $DIR/destructure_patterns.rs:92:21
    |
-LL |         let Point { x, y } = p; // 1
+LL |         let Point { x, y } = p;
    |                     ^ help: try ignoring the field: `x: _`
 
 warning: unused variable: `x`
-  --> $DIR/destructure_patterns.rs:85:9
+  --> $DIR/destructure_patterns.rs:84:9
    |
 LL |     let x = 0;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 warning: unused variable: `tup`
-  --> $DIR/destructure_patterns.rs:87:9
+  --> $DIR/destructure_patterns.rs:86:9
    |
 LL |     let tup = (1, 2);
    |         ^^^ help: if this is intentional, prefix it with an underscore: `_tup`
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs
new file mode 100644
index 00000000000..dae50854d82
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs
@@ -0,0 +1,12 @@
+//check-pass
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![feature(rustc_attrs)]
+
+fn main() {
+    let mut x = 1;
+    let c = || {
+        drop(&mut x);
+        match x { _ => () }
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr
index 66171f35763..7f811875d13 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr
@@ -1,5 +1,5 @@
 warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/struct_update_syntax.rs:2:12
+  --> $DIR/drop_then_use_fake_reads.rs:2:12
    |
 LL | #![feature(capture_disjoint_fields)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs
index 97b56e7c4be..9c086fe4bdf 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs
@@ -21,4 +21,11 @@ fn main() {
         assert!(matches!(result, Ok(None)));
     }
 
+    {
+        let mut it = map.drain_filter(|_, _| true);
+        catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err();
+        let result = catch_unwind(AssertUnwindSafe(|| it.next()));
+        assert!(matches!(result, Ok(None)));
+    }
+
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs
index 2f13590a2bd..d260a448926 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs
@@ -11,6 +11,7 @@ enum PointType {
     ThreeD{ x: u32, y: u32, z: u32 }
 }
 
+// Testing struct patterns
 struct Points {
     points: Vec<PointType>,
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs
deleted file mode 100644
index 34710e69b96..00000000000
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//check-pass
-#![feature(capture_disjoint_fields)]
-//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
-#![feature(rustc_attrs)]
-
-struct S {
-    a: String,
-    b: String,
-}
-
-fn main() {
-    let s = S {
-        a: String::new(),
-        b: String::new(),
-    };
-
-    let c = || {
-        let s2 = S {
-            a: format!("New a"),
-            ..s
-        };
-    };
-
-    c();
-}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs
index 0948039287b..b3bee79254e 100644
--- a/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs
@@ -8,6 +8,7 @@ enum PointType {
     ThreeD(u32, u32, u32)
 }
 
+// Testing tuple struct patterns
 struct Points {
     points: Vec<PointType>,
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs
new file mode 100644
index 00000000000..0e6da8f4f18
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs
@@ -0,0 +1,12 @@
+//check-pass
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![feature(rustc_attrs)]
+
+fn main() {
+    let mut x = 0;
+    let c = || {
+        &mut x; // mutable borrow of `x`
+        match x { _ => () } // fake read of `x`
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr
new file mode 100644
index 00000000000..7d16d77bf73
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/use_of_mutable_borrow_and_fake_reads.rs:2:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index a3469ee2114..285c203f382 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -189,19 +189,18 @@ LL |     drop(_x3);
 error[E0382]: use of moved value: `tup`
   --> $DIR/borrowck-move-ref-pattern.rs:43:14
    |
-LL |       let mut tup = (U, U, U);
-   |           ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
-LL |       let c1 = || {
-   |                -- value moved into closure here
-LL |           let (ref _x0, _x1, _) = tup;
-   |                                   --- variable moved due to use in closure
-LL |       };
-LL |       let c2 = || {
-   |  ______________^
-LL | |
-LL | |         let (ref mut _x0, _, _x2) = tup;
-LL | |     };
-   | |_____^ value used here after move
+LL |     let mut tup = (U, U, U);
+   |         ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
+LL |     let c1 = || {
+   |              -- value moved into closure here
+LL |         let (ref _x0, _x1, _) = tup;
+   |                                 --- variable moved due to use in closure
+LL |     };
+LL |     let c2 = || {
+   |              ^^ value used here after move
+LL |
+LL |         let (ref mut _x0, _, _x2) = tup;
+   |                                     --- use occurs due to use in closure
 
 error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 6994e9f7d2e..97216757547 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -186,7 +186,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
         }
     }
 
-    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { }
+    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { }
 }
 
 impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index d5a9d5e4e13..d439577f9c3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -335,5 +335,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
 
     fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
 
-    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { }
+    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { }
 }
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 8aa8781f6be..0b1ab6b7ea1 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -79,7 +79,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
         self.update(&cmt)
     }
 
-    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { }
+    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { }
 }
 
 pub struct ParamBindingIdCollector {