about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs34
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs33
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs90
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs103
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs11
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs15
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs37
13 files changed, 177 insertions, 179 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2d1231d819d..425e62d6f61 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -47,6 +47,7 @@ use rustc_hir::{
 };
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
+use rustc_middle::mir::FakeReadCause;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
@@ -430,8 +431,7 @@ pub struct TypeckResults<'tcx> {
     /// see `MinCaptureInformationMap` for more details.
     pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
 
-    /// [FIXME] RFC2229 Change to use HashSet instead of Vec
-    pub closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>>,
+    pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause)>>,
 
     /// 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/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index ae4d6b56152..808c6e3ff64 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -94,14 +94,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         )
                     );
                 }
-                // ROX:
-                //
-                // Where the handling of destructure patterns start
-                //
-                // let (a, b, c, _ ) = something
-                //
-                // (a, b, c, _) is the pattern
-                // something is the initializer
                 StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
                     let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
@@ -133,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                             ArmHasGuard(false),
                                             Some((None, initializer_span)),
                                         );
-                                        // This is where we get into pattern handling of the let
-                                        // statement
                                         this.expr_into_pattern(block, pattern.clone(), init)
                                     })
                                 }
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 f819a638c7a..6519d5fae1c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -84,6 +84,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
     mir_projections: &[PlaceElem<'tcx>],
 ) -> Vec<HirProjectionKind> {
     let mut hir_projections = Vec::new();
+    let mut variant = None;
 
     for mir_projection in mir_projections {
         let hir_projection = match mir_projection {
@@ -91,13 +92,17 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
             ProjectionElem::Field(field, _) => {
                 // We will never encouter this for multivariant enums,
                 // read the comment for `Downcast`.
-                HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0))
+                let variant = variant.unwrap_or(VariantIdx::new(0));
+                HirProjectionKind::Field(field.index() as u32, variant)
             }
-            ProjectionElem::Downcast(..) => {
-                // This projections exist only for enums that have
-                // multiple variants. Since such enums that are captured
-                // completely, we can stop here.
-                break;
+            ProjectionElem::Downcast(.., idx) => {
+                // This projections exist for enums that have
+                // single and multiple variants.
+                // For single variants, enums are not captured completely.
+                // We keep track of VariantIdx so we can use this information
+                // if the next ProjectionElem is a Field
+                variant = Some(*idx);
+                continue;
             }
             ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
@@ -107,7 +112,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
                 break;
             }
         };
-
+        variant = None;
         hir_projections.push(hir_projection);
     }
 
@@ -231,13 +236,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
                         from_builder.projection
                     )
                 } else {
-                    // FIXME(project-rfc-2229#24): Handle this case properly
                     debug!(
                         "No associated capture found for {:?}[{:#?}]",
                         var_hir_id, from_builder.projection,
                     );
                 }
-                return Err(upvar_resolved_place_builder);
+                return Err(from_builder);
             };
 
             let closure_ty = typeck_results
@@ -289,11 +293,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
         if let PlaceBase::Local(local) = self.base {
             Place { local, projection: tcx.intern_place_elems(&self.projection) }
         } else {
-            self.try_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
+            self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
         }
     }
 
-    /// ROX: Function that will be called when we really do need a place
     fn expect_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
@@ -302,14 +305,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
         to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
     }
 
-    fn try_upvars_resolved<'a>(
+    crate fn try_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
-    ) -> PlaceBuilder<'tcx> {
+    ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
         match to_upvars_resolved_place_builder(self, tcx, typeck_results) {
-            Ok(upvars_resolved) => upvars_resolved,
-            Err(upvars_unresolved) => upvars_unresolved,
+            Ok(upvars_resolved) => Ok(upvars_resolved),
+            Err(upvars_unresolved) => Err(upvars_unresolved),
         }
     }
 
@@ -376,7 +379,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block.and(place_builder.into_place(self.tcx, self.typeck_results))
     }
 
-    // ROX: As place builder
     /// This is used when constructing a compound `Place`, so that we can avoid creating
     /// intermediate `Place` values until we know the full set of projections.
     crate fn as_place_builder(
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 3a8665777b7..c7f16fd4e40 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -165,7 +165,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
-            ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => {
+            ExprKind::Closure {
+                closure_id,
+                substs,
+                upvars,
+                movability,
+                fake_reads: opt_fake_reads,
+            } => {
                 // see (*) above
                 let operands: Vec<_> = upvars
                     .into_iter()
@@ -204,18 +210,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         }
                     })
                     .collect();
-
-                if let Some(fake_reads) = fake_reads {
-                    for thir_place in fake_reads.into_iter() {
-                        //  = this.hir.mirror(thir_place);
-                        let mir_place = unpack!(block = this.as_place(block, thir_place));
-                        // [FIXME] RFC2229 FakeReadCause can be ForLet or ForMatch, need to use the correct one
-                        this.cfg.push_fake_read(
-                            block,
-                            source_info,
-                            FakeReadCause::ForMatchedPlace,
-                            mir_place,
-                        );
+                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);
+                        }
                     }
                 }
 
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index e0ad34e08ef..b2e8b2de1bc 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -280,7 +280,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let field_names: Vec<_> =
                     (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
 
-                // ROX: This is probably here the function record/struct update pattern is done.
                 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
                     let place_builder = unpack!(block = this.as_place_builder(block, base));
 
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 7285cf75623..59b3fd86478 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1,6 +1,3 @@
-// ROX: this folder contains all code for handling patterns, including exhaustiveness checking etc.
-// We want to be careful ^^'
-
 //! Code related to match expressions. These are sufficiently complex to
 //! warrant their own module and submodules. :) This main module includes the
 //! high-level algorithm, the submodules contain the details.
@@ -100,7 +97,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let scrutinee_place =
             unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
 
-        let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
+        let mut arm_candidates =
+            self.create_match_candidates(scrutinee_place.clone(), &arms.clone());
 
         let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
         let mut candidates =
@@ -127,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         scrutinee_span: Span,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
-        let scrutinee_place =
-            scrutinee_place_builder.clone().into_place(self.tcx, self.typeck_results);
         // Matching on a `scrutinee_place` with an uninhabited type doesn't
         // generate any memory reads by itself, and so if the place "expression"
         // contains unsafe operations like raw pointer dereferences or union
@@ -146,7 +142,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // check safety.
         let cause_matched_place = FakeReadCause::ForMatchedPlace;
         let source_info = self.source_info(scrutinee_span);
-        self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
+
+        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);
+            self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
+        }
 
         block.and(scrutinee_place_builder)
     }
@@ -228,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_match_arms(
         &mut self,
         destination: Place<'tcx>,
-        scrutinee_place: PlaceBuilder<'tcx>,
+        scrutinee_place_builder: PlaceBuilder<'tcx>,
         scrutinee_span: Span,
         arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>,
         outer_source_info: SourceInfo,
@@ -242,17 +245,23 @@ 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 mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
+                    let scrutinee_place: Place<'tcx>;
+                    if let Ok(scrutinee_builder) = scrutinee_place_builder
+                        .clone()
+                        .try_upvars_resolved(this.tcx, this.typeck_results)
+                    {
+                        scrutinee_place =
+                            scrutinee_builder.clone().into_place(this.tcx, this.typeck_results);
+                        opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
+                    }
                     let scope = this.declare_bindings(
                         None,
                         arm.span,
                         &arm.pattern,
                         ArmHasGuard(arm.guard.is_some()),
-                        Some((
-                            Some(
-                                &scrutinee_place.clone().into_place(this.tcx, this.typeck_results),
-                            ),
-                            scrutinee_span,
-                        )),
+                        opt_scrutinee_place,
                     );
 
                     let arm_block = this.bind_pattern(
@@ -457,15 +466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             _ => {
-                // Converts the destruct pattern into a place
-                //
-                // We don't want to convert to a place right away
-                // because in case of such pattern inside a closure, the projections matching a
-                // captured place might have not been applied.
-                // [FIXME] Need to find where this is happening and make the necessary changes there once
-                // Candidate is modified
-                //
-                // We want to use a place builder; Maybe use `as_place_builder`
                 let place_builder = unpack!(block = self.as_place_builder(block, initializer));
                 self.place_into_pattern(block, irrefutable_pat, place_builder, true)
             }
@@ -479,12 +479,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         initializer: PlaceBuilder<'tcx>,
         set_match_place: bool,
     ) -> BlockAnd<()> {
-        let place = initializer.clone().into_place(self.tcx, self.typeck_results);
-        let mut candidate = Candidate::new(initializer, &irrefutable_pat, false);
-
+        let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
         let fake_borrow_temps =
             self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
-
         // For matches and function arguments, the place that is being matched
         // can be set when creating the variables. But the place for
         // let PATTERN = ... might not even exist until we do the assignment.
@@ -499,7 +496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
                     )))) = self.local_decls[local].local_info
                     {
-                        *match_place = Some(place);
+                        if let Ok(match_pair_resolved) =
+                            initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                        {
+                            let place = match_pair_resolved
+                                .clone()
+                                .into_place(self.tcx, self.typeck_results);
+                            *match_place = Some(place);
+                        }
                     } else {
                         bug!("Let binding to non-user variable.")
                     }
@@ -1461,7 +1465,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         // Insert a Shallow borrow of any places that is switched on.
         if let Some(fb) = fake_borrows {
-            fb.insert(match_place.clone().into_place(self.tcx, self.typeck_results));
+            if let Ok(match_place_resolved) =
+                match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+            {
+                let resolved_place =
+                    match_place_resolved.clone().into_place(self.tcx, self.typeck_results);
+                fb.insert(resolved_place);
+            }
         }
 
         // perform the test, branching to one of N blocks. For each of
@@ -1776,28 +1786,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
                 Guard::IfLet(pat, scrutinee) => {
                     let scrutinee_span = scrutinee.span;
-                    let scrutinee_place = unpack!(
+                    let scrutinee_place_builder = unpack!(
                         block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)
                     );
-                    let mut guard_candidate = Candidate::new(scrutinee_place.clone(), &pat, false);
+                    let mut guard_candidate =
+                        Candidate::new(scrutinee_place_builder.clone(), &pat, false);
                     let wildcard = Pat::wildcard_from_ty(pat.ty);
                     let mut otherwise_candidate =
-                        Candidate::new(scrutinee_place.clone(), &wildcard, false);
+                        Candidate::new(scrutinee_place_builder.clone(), &wildcard, false);
                     let fake_borrow_temps = self.lower_match_tree(
                         block,
                         pat.span,
                         false,
                         &mut [&mut guard_candidate, &mut otherwise_candidate],
                     );
+                    let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
+                    let scrutinee_place: Place<'tcx>;
+                    if let Ok(scrutinee_builder) = scrutinee_place_builder
+                        .clone()
+                        .try_upvars_resolved(self.tcx, self.typeck_results)
+                    {
+                        scrutinee_place =
+                            scrutinee_builder.clone().into_place(self.tcx, self.typeck_results);
+                        opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
+                    }
                     self.declare_bindings(
                         None,
                         pat.span.to(arm_span.unwrap()),
                         pat,
                         ArmHasGuard(false),
-                        Some((
-                            Some(&scrutinee_place.clone().into_place(tcx, self.typeck_results)),
-                            scrutinee.span,
-                        )),
+                        opt_scrutinee_place,
                     );
                     let post_guard_block = self.bind_pattern(
                         self.source_info(pat.span),
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index d9c1d4abf07..dc4f2886456 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -149,9 +149,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidate: &mut Candidate<'pat, 'tcx>,
     ) -> Result<(), MatchPair<'pat, 'tcx>> {
         let tcx = self.tcx;
-        // Generate place to be used in Ascription
-        // Generate place to be used in Binding
-        let place = match_pair.place.clone().into_place(tcx, self.typeck_results);
         match *match_pair.pattern.kind {
             PatKind::AscribeUserType {
                 ref subpattern,
@@ -159,6 +156,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
                 // value being matched, taking the variance field into account.
+                let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
                 candidate.ascriptions.push(Ascription {
                     span: user_ty_span,
                     user_ty,
@@ -177,6 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
+                let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
                 candidate.bindings.push(Binding {
                     name,
                     mutability,
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index b804cd4574f..02f1998f496 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -156,7 +156,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         test: &Test<'tcx>,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
     ) {
-        let place = place_builder.clone().into_place(self.tcx, self.typeck_results);
+        let place: Place<'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);
+        } else {
+            return;
+        }
         debug!(
             "perform_test({:?}, {:?}: {:?}, {:?})",
             block,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 25e08efb2e3..6b7bd2e9dcc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -455,27 +455,32 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 );
 
                 let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
-                    Some(vals) => Some(self.arena.alloc_from_iter(vals
-                        .iter()
-                        .filter(|val| match val.base {
-                            HirPlaceBase::Upvar(_) => true,
-                            _ => false,
-                        })
-                        .map(|val| {
-                            let var_hir_id = match val.base {
-                                HirPlaceBase::Upvar(upvar_id) => {
-                                    debug!("upvar");
-                                    upvar_id.var_path.hir_id
-                                }
-                                _ => {
-                                    bug!(
-                                        "Do not know how to get HirId out of Rvalue and StaticItem"
-                                    );
-                                }
-                            };
-                            self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
-                        })
-                    )),
+                    Some(vals) => {
+                        Some(
+                            vals.iter()
+                                .map(|(place, cause)| {
+                                    (
+                                        self.arena.alloc(
+                                            self.convert_captured_hir_place(expr, place.clone()),
+                                        ),
+                                        *cause,
+                                    )
+                                    // let var_hir_id = match val.base {
+                                    //     HirPlaceBase::Upvar(upvar_id) => {
+                                    //         debug!("upvar");
+                                    //         upvar_id.var_path.hir_id
+                                    //     }
+                                    //     _ => {
+                                    //         bug!(
+                                    //             "Do not know how to get HirId out of Rvalue and StaticItem"
+                                    //         );
+                                    //     }
+                                    // };
+                                    // self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
+                                })
+                                .collect(),
+                        )
+                    }
                     None => None,
                 };
 
@@ -1045,23 +1050,26 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         ExprKind::Deref { arg: ref_expr }
     }
 
-    fn fake_read_capture_upvar(
+    fn convert_captured_hir_place(
         &mut self,
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
-        hir_id: hir::HirId,
     ) -> Expr<'thir, 'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
+        let var_hir_id = match place.base {
+            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+            base => bug!("Expected an upvar, found {:?}", base),
+        };
+
         let mut captured_place_expr = Expr {
             temp_lifetime,
             ty: var_ty,
             span: closure_expr.span,
-            kind: self.convert_var(hir_id),
+            kind: self.convert_var(var_hir_id),
         };
-        // [FIXME] RFC2229 Maybe we should introduce an immutable borrow of the fake capture so that we don't
-        // end up moving this place
+
         for proj in place.projections.iter() {
             let kind = match proj.kind {
                 HirProjectionKind::Deref => {
@@ -1095,48 +1103,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         upvar_ty: Ty<'tcx>,
     ) -> Expr<'thir, 'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
+        let captured_place_expr =
+            self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
-        let var_ty = captured_place.place.base_ty;
-
-        // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
-        // as it's seen for use within the closure and not at the time of closure creation.
-        //
-        // That is we see expect to see it start from a captured upvar and not something that is local
-        // to the closure's parent.
-        let var_hir_id = match captured_place.place.base {
-            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
-            base => bug!("Expected an upvar, found {:?}", base),
-        };
-
-        let mut captured_place_expr = Expr {
-            temp_lifetime,
-            ty: var_ty,
-            span: closure_expr.span,
-            kind: self.convert_var(var_hir_id),
-        };
-
-        for proj in captured_place.place.projections.iter() {
-            let kind = match proj.kind {
-                HirProjectionKind::Deref => {
-                    ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
-                }
-                HirProjectionKind::Field(field, ..) => {
-                    // Variant index will always be 0, because for multi-variant
-                    // enums, we capture the enum entirely.
-                    ExprKind::Field {
-                        lhs: self.arena.alloc(captured_place_expr),
-                        name: Field::new(field as usize),
-                    }
-                }
-                HirProjectionKind::Index | HirProjectionKind::Subslice => {
-                    // We don't capture these projections, so we can ignore them here
-                    continue;
-                }
-            };
-
-            captured_place_expr =
-                Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
-        }
 
         match upvar_capture {
             ty::UpvarCapture::ByValue(_) => captured_place_expr,
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index 730c0f4a3df..a6ec3b7bdd2 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -9,7 +9,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
-use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
@@ -281,7 +281,7 @@ pub enum ExprKind<'thir, 'tcx> {
         substs: UpvarSubsts<'tcx>,
         upvars: &'thir [Expr<'thir, 'tcx>],
         movability: Option<hir::Movability>,
-        fake_reads: Option<&'thir mut [Expr<'thir, 'tcx>]>,
+        fake_reads: Option<Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause)>>,
     },
     Literal {
         literal: &'tcx Const<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 932f07ff1bd..9a43eaa3f5d 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -34,7 +34,6 @@ use super::writeback::Resolver;
 use super::FnCtxt;
 
 use crate::expr_use_visitor as euv;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -42,6 +41,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
+use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
 use rustc_session::lint;
@@ -248,7 +248,8 @@ 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(|fake_read| fake_read).collect();
+        let fake_reads =
+            delegate.fake_reads.into_iter().map(|(place, cause)| (place, cause)).collect();
         self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
 
         // If we are also inferred the closure kind here,
@@ -1153,7 +1154,7 @@ struct InferBorrowKind<'a, 'tcx> {
     /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
     /// ```
     capture_information: InferredCaptureInformation<'tcx>,
-    fake_reads: FxHashSet<Place<'tcx>>, // these need to be fake read.
+    fake_reads: Vec<(Place<'tcx>, FakeReadCause)>,
 }
 
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@@ -1415,9 +1416,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>) {
+    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause) {
         if let PlaceBase::Upvar(_) = place.base {
-            self.fake_reads.insert(place);
+            self.fake_reads.push((place, cause));
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 9cccda7768c..1be629ce9dc 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -12,6 +12,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::Place as HirPlace;
+use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -368,18 +369,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     }
 
     fn visit_fake_reads_map(&mut self) {
-        let mut resolved_closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>> =
-            Default::default();
+        let mut resolved_closure_fake_reads: FxHashMap<
+            DefId,
+            Vec<(HirPlace<'tcx>, FakeReadCause)>,
+        > = 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>>::new();
-            for fake_read in fake_reads.iter() {
+            let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause)>::new();
+            for (place, cause) 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(fake_read.clone(), &locatable);
-                resolved_fake_reads.push(resolved_fake_read);
+                let resolved_fake_read = self.resolve(place.clone(), &locatable);
+                resolved_fake_reads.push((resolved_fake_read, *cause));
             }
             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 ad39b93c067..6dbf8094548 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -8,13 +8,14 @@ pub use self::ConsumeMode::*;
 pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
 
 use rustc_hir as hir;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
-// use rustc_hir::Pat;
 use rustc_hir::PatKind;
+use rustc_hir::QPath;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::ProjectionKind;
+use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, adjustment, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
@@ -54,7 +55,7 @@ pub trait Delegate<'tcx> {
     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
 
     // [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27
-    fn fake_read(&mut self, place: Place<'tcx>);
+    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause);
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -237,18 +238,26 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 // We only want to borrow discr if the pattern contain something other
                 // than wildcards
                 let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
-                let mut res = false;
+                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| {
                         if let PatKind::Binding(_, _, _, opt_sub_pat) = pat.kind {
                             if let None = opt_sub_pat {
-                                res = true;
+                                needs_to_be_read = true;
+                            }
+                        } else if let PatKind::TupleStruct(qpath, _, _) = &pat.kind {
+                            // If a TupleStruct has a Some PathSegment, we should read the discr_place
+                            // regardless if it contains a Wild pattern later
+                            if let QPath::Resolved(_, path) = qpath {
+                                if let Res::Def(DefKind::Ctor(_, _), _) = path.res {
+                                    needs_to_be_read = true;
+                                }
                             }
                         }
                     }));
                 }
 
-                if res {
+                if needs_to_be_read {
                     self.borrow_expr(&discr, ty::ImmBorrow);
                 }
 
@@ -539,6 +548,7 @@ 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.walk_pat(discr_place, &arm.pat);
 
         if let Some(hir::Guard::If(ref e)) = arm.guard {
@@ -551,6 +561,7 @@ 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.walk_pat(discr_place, pat);
     }
 
@@ -558,8 +569,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
         debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
 
-        self.delegate.fake_read(discr_place.place.clone());
-
         let tcx = self.tcx();
         let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
         return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
@@ -620,10 +629,6 @@ 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<'_>) {
-        // Over here we walk a closure that is nested inside the current body
-        // If the current body is a closure, then we also want to report back any fake reads,
-        // starting off of variables that are captured by our parent as well.
-
         let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
         let upvars = self.tcx().upvars_mentioned(self.body_owner);
 
@@ -633,15 +638,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             ty::Closure(..) | ty::Generator(..)
         );
 
-        // [FIXME] RFC2229 Closures within closures don't work
         if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
-            for fake_read in fake_reads.iter() {
-                // Use this as a reference for if we should promote the fake read
+            for (fake_read, cause) 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)
                         }) {
+                            // [FIXME] RFC2229 Update this comment
                             // The nested closure might be capturing 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 aren't captures, we will ignore them.
@@ -655,14 +659,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         );
                     }
                 };
-                self.delegate.fake_read(fake_read.clone());
+                self.delegate.fake_read(fake_read.clone(), *cause);
             }
         }
 
         if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
         {
             for (var_hir_id, min_list) in min_captures.iter() {
-                // Use this as a reference for if we should promote the fake read
                 if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
                     // The nested closure might be capturing the current (enclosing) closure's local variables.
                     // We check if the root variable is ever mentioned within the enclosing closure, if not