]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #100968 - cjgillot:mir-upvar-vec, r=wesleywiser
authorbors <bors@rust-lang.org>
Sat, 10 Sep 2022 12:07:29 +0000 (12:07 +0000)
committerbors <bors@rust-lang.org>
Sat, 10 Sep 2022 12:07:29 +0000 (12:07 +0000)
Only compute captures once when building MIR.

compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/simplify.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/matches/util.rs
compiler/rustc_mir_build/src/build/mod.rs

index 46dbd8a136b52f1f10017e052c2bbcd68ffe0233..ebb56e5a23365d636996c1b053825e9a463b3a6b 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
@@ -59,8 +59,6 @@ pub(crate) enum PlaceBase {
         var_hir_id: LocalVarId,
         /// DefId of the closure
         closure_def_id: LocalDefId,
-        /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
-        closure_kind: ty::ClosureKind,
     },
 }
 
@@ -145,27 +143,6 @@ fn is_ancestor_or_same_capture(
     iter::zip(proj_possible_ancestor, proj_capture).all(|(a, b)| a == b)
 }
 
-/// Computes the index of a capture within the desugared closure provided the closure's
-/// `closure_min_captures` and the capture's index of the capture in the
-/// `ty::MinCaptureList` of the root variable `var_hir_id`.
-fn compute_capture_idx<'tcx>(
-    closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
-    var_hir_id: LocalVarId,
-    root_var_idx: usize,
-) -> usize {
-    let mut res = 0;
-    for (var_id, capture_list) in closure_min_captures {
-        if *var_id == var_hir_id.0 {
-            res += root_var_idx;
-            break;
-        } else {
-            res += capture_list.len();
-        }
-    }
-
-    res
-}
-
 /// Given a closure, returns the index of a capture within the desugared closure struct and the
 /// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id`
 /// and `projection`.
@@ -174,27 +151,17 @@ fn compute_capture_idx<'tcx>(
 ///
 /// Returns None, when the ancestor is not found.
 fn find_capture_matching_projections<'a, 'tcx>(
-    typeck_results: &'a ty::TypeckResults<'tcx>,
+    upvars: &'a CaptureMap<'tcx>,
     var_hir_id: LocalVarId,
-    closure_def_id: LocalDefId,
     projections: &[PlaceElem<'tcx>],
-) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
-    let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
-    let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?;
-
+) -> Option<(usize, &'a Capture<'tcx>)> {
     let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
 
-    // If an ancestor is found, `idx` is the index within the list of captured places
-    // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
-    let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| {
+    upvars.get_by_key_enumerated(var_hir_id.0).find(|(_, capture)| {
         let possible_ancestor_proj_kinds: Vec<_> =
-            capture.place.projections.iter().map(|proj| proj.kind).collect();
+            capture.captured_place.place.projections.iter().map(|proj| proj.kind).collect();
         is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
-    })?;
-
-    // Convert index to be from the perspective of the entire closure_min_captures map
-    // instead of just the root variable capture list
-    Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture))
+    })
 }
 
 /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
@@ -204,24 +171,15 @@ fn find_capture_matching_projections<'a, 'tcx>(
 fn to_upvars_resolved_place_builder<'a, 'tcx>(
     from_builder: PlaceBuilder<'tcx>,
     tcx: TyCtxt<'tcx>,
-    typeck_results: &'a ty::TypeckResults<'tcx>,
+    upvars: &'a CaptureMap<'tcx>,
 ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
     match from_builder.base {
         PlaceBase::Local(_) => Ok(from_builder),
-        PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
-            let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
-            match closure_kind {
-                ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
-                    upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
-                }
-                ty::ClosureKind::FnOnce => {}
-            }
-
+        PlaceBase::Upvar { var_hir_id, closure_def_id } => {
             let Some((capture_index, capture)) =
                 find_capture_matching_projections(
-                    typeck_results,
+                    upvars,
                     var_hir_id,
-                    closure_def_id,
                     &from_builder.projection,
                 ) else {
                 let closure_span = tcx.def_span(closure_def_id);
@@ -241,39 +199,17 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
                 return Err(from_builder);
             };
 
-            // We won't be building MIR if the closure wasn't local
-            let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id);
-            let closure_ty = typeck_results.node_type(closure_hir_id);
-
-            let substs = match closure_ty.kind() {
-                ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
-                ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
-                _ => bug!("Lowering capture for non-closure type {:?}", closure_ty),
-            };
-
             // Access the capture by accessing the field within the Closure struct.
-            //
-            // We must have inferred the capture types since we are building MIR, therefore
-            // it's safe to call `tuple_element_ty` and we can unwrap here because
-            // we know that the capture exists and is the `capture_index`-th capture.
-            let var_ty = substs.tupled_upvars_ty().tuple_fields()[capture_index];
-
-            upvar_resolved_place_builder =
-                upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
-
-            // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
-            // we need to deref it
-            upvar_resolved_place_builder = match capture.info.capture_kind {
-                ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
-                ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
-            };
+            let capture_info = &upvars[capture_index];
+
+            let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
 
             // We used some of the projections to build the capture itself,
             // now we apply the remaining to the upvar resolved place.
             let remaining_projections = strip_prefix(
-                capture.place.base_ty,
+                capture.captured_place.place.base_ty,
                 from_builder.projection,
-                &capture.place.projections,
+                &capture.captured_place.place.projections,
             );
             upvar_resolved_place_builder.projection.extend(remaining_projections);
 
@@ -315,24 +251,24 @@ fn strip_prefix<'tcx>(
 }
 
 impl<'tcx> PlaceBuilder<'tcx> {
-    pub(crate) fn into_place<'a>(
+    pub(in crate::build) fn into_place<'a>(
         self,
         tcx: TyCtxt<'tcx>,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
+        upvars: &'a CaptureMap<'tcx>,
     ) -> Place<'tcx> {
         if let PlaceBase::Local(local) = self.base {
             Place { local, projection: tcx.intern_place_elems(&self.projection) }
         } else {
-            self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
+            self.expect_upvars_resolved(tcx, upvars).into_place(tcx, upvars)
         }
     }
 
     fn expect_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
+        upvars: &'a CaptureMap<'tcx>,
     ) -> PlaceBuilder<'tcx> {
-        to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
+        to_upvars_resolved_place_builder(self, tcx, upvars).unwrap()
     }
 
     /// Attempts to resolve the `PlaceBuilder`.
@@ -346,12 +282,12 @@ fn expect_upvars_resolved<'a>(
     /// 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.
-    pub(crate) fn try_upvars_resolved<'a>(
+    pub(in crate::build) fn try_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
+        upvars: &'a CaptureMap<'tcx>,
     ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
-        to_upvars_resolved_place_builder(self, tcx, typeck_results)
+        to_upvars_resolved_place_builder(self, tcx, upvars)
     }
 
     pub(crate) fn base(&self) -> PlaceBase {
@@ -392,6 +328,12 @@ fn from(base: PlaceBase) -> Self {
     }
 }
 
+impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
+    fn from(p: Place<'tcx>) -> Self {
+        Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() }
+    }
+}
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a place that we can move from etc.
     ///
@@ -411,7 +353,7 @@ pub(crate) fn as_place(
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place(self.tcx, self.typeck_results))
+        block.and(place_builder.into_place(self.tcx, &self.upvars))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -435,7 +377,7 @@ pub(crate) fn as_read_only_place(
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place(self.tcx, self.typeck_results))
+        block.and(place_builder.into_place(self.tcx, &self.upvars))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -530,7 +472,7 @@ fn expr_as_place(
                             inferred_ty: expr.ty,
                         });
 
-                    let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
+                    let place = place_builder.clone().into_place(this.tcx, &this.upvars);
                     this.cfg.push(
                         block,
                         Statement {
@@ -629,17 +571,7 @@ fn lower_captured_upvar(
         closure_def_id: LocalDefId,
         var_hir_id: LocalVarId,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        let closure_ty =
-            self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_def_id));
-
-        let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
-            self.infcx.closure_kind(closure_substs).unwrap()
-        } else {
-            // Generators are considered FnOnce.
-            ty::ClosureKind::FnOnce
-        };
-
-        block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind }))
+        block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id }))
     }
 
     /// Lower an index expression
@@ -678,7 +610,7 @@ fn lower_index_expression(
         if is_outermost_index {
             self.read_fake_borrows(block, fake_borrow_temps, source_info)
         } else {
-            base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
+            base_place = base_place.expect_upvars_resolved(self.tcx, &self.upvars);
             self.add_fake_borrows_of_base(
                 &base_place,
                 block,
@@ -710,7 +642,7 @@ fn bounds_check(
             block,
             source_info,
             len,
-            Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
+            Rvalue::Len(slice.into_place(self.tcx, &self.upvars)),
         );
         // lt = idx < len
         self.cfg.push_assign(
index 4b232a1b515302fa1317dba9d2cc921d4026a501..c1282b8ddaff47c20d314297479d38d443bb10d5 100644 (file)
@@ -328,10 +328,9 @@ pub(crate) fn as_rvalue(
                         unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
 
                     if let Ok(place_builder_resolved) =
-                        place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
+                        place_builder.try_upvars_resolved(this.tcx, &this.upvars)
                     {
-                        let mir_place =
-                            place_builder_resolved.into_place(this.tcx, this.typeck_results);
+                        let mir_place = place_builder_resolved.into_place(this.tcx, &this.upvars);
                         this.cfg.push_fake_read(
                             block,
                             this.source_info(this.tcx.hir().span(*hir_id)),
@@ -623,7 +622,7 @@ fn limit_capture_mutability(
             // is same as that of the capture in the parent closure.
             PlaceBase::Upvar { .. } => {
                 let enclosing_upvars_resolved =
-                    arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
+                    arg_place_builder.clone().into_place(this.tcx, &this.upvars);
 
                 match enclosing_upvars_resolved.as_ref() {
                     PlaceRef {
@@ -643,12 +642,12 @@ fn limit_capture_mutability(
                         );
                         // Not in a closure
                         debug_assert!(
-                            this.upvar_mutbls.len() > upvar_index.index(),
-                            "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
-                            this.upvar_mutbls,
+                            this.upvars.len() > upvar_index.index(),
+                            "Unexpected capture place, upvars={:#?}, upvar_index={:?}",
+                            this.upvars,
                             upvar_index
                         );
-                        this.upvar_mutbls[upvar_index.index()]
+                        this.upvars[upvar_index.index()].mutability
                     }
                     _ => bug!("Unexpected capture place"),
                 }
@@ -660,7 +659,7 @@ fn limit_capture_mutability(
             Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
         };
 
-        let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
+        let arg_place = arg_place_builder.into_place(this.tcx, &this.upvars);
 
         this.cfg.push_assign(
             block,
index 74509646c17c698f6ca4dc810b2d84447123938b..6ed5f1fc0d34845462876af340994cfda08d7618 100644 (file)
@@ -366,9 +366,7 @@ pub(crate) fn expr_into_dest(
                             None => {
                                 let place_builder = place_builder.clone();
                                 this.consume_by_copy_or_move(
-                                    place_builder
-                                        .field(n, *ty)
-                                        .into_place(this.tcx, this.typeck_results),
+                                    place_builder.field(n, *ty).into_place(this.tcx, &this.upvars),
                                 )
                             }
                         })
index a316c2e7d6e187bf1d25a5b7da4c33543cf89695..505273033a4ca3c357c167205bcf9ec67292a8a1 100644 (file)
@@ -221,9 +221,9 @@ fn lower_scrutinee(
         let source_info = self.source_info(scrutinee_span);
 
         if let Ok(scrutinee_builder) =
-            scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+            scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, &self.upvars)
         {
-            let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
+            let scrutinee_place = scrutinee_builder.into_place(self.tcx, &self.upvars);
             self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
         }
 
@@ -348,12 +348,10 @@ fn lower_match_arms(
                     // ```
                     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)
+                    if let Ok(scrutinee_builder) =
+                        scrutinee_place_builder.clone().try_upvars_resolved(this.tcx, &this.upvars)
                     {
-                        scrutinee_place =
-                            scrutinee_builder.into_place(this.tcx, this.typeck_results);
+                        scrutinee_place = scrutinee_builder.into_place(this.tcx, &this.upvars);
                         opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
                     }
                     let scope = this.declare_bindings(
@@ -620,9 +618,9 @@ pub(crate) fn place_into_pattern(
                     // };
                     // ```
                     if let Ok(match_pair_resolved) =
-                        initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                        initializer.clone().try_upvars_resolved(self.tcx, &self.upvars)
                     {
-                        let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
+                        let place = match_pair_resolved.into_place(self.tcx, &self.upvars);
                         *match_place = Some(place);
                     }
                 }
@@ -1602,9 +1600,9 @@ fn test_candidates<'pat, 'b, 'c>(
 
         // Insert a Shallow borrow of any places that is switched on.
         if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
-            match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+            match_place.clone().try_upvars_resolved(self.tcx, &self.upvars)
         {
-            let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
+            let resolved_place = match_place_resolved.into_place(self.tcx, &self.upvars);
             fb.insert(resolved_place);
         }
 
@@ -1791,10 +1789,8 @@ pub(crate) fn lower_let_expr(
         );
         let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
         let expr_place: Place<'tcx>;
-        if let Ok(expr_builder) =
-            expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
-        {
-            expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
+        if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
+            expr_place = expr_builder.into_place(self.tcx, &self.upvars);
             opt_expr_place = Some((Some(&expr_place), expr_span));
         }
         let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
index 55ed09da64fb866162cddda8d9d6809d360c6f5f..df221d356038451da21f71b9a3f32e9def014824 100644 (file)
@@ -156,11 +156,11 @@ fn simplify_match_pair<'pat>(
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
                 if let Ok(place_resolved) =
-                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
                 {
                     candidate.ascriptions.push(Ascription {
                         annotation: annotation.clone(),
-                        source: place_resolved.into_place(self.tcx, self.typeck_results),
+                        source: place_resolved.into_place(self.tcx, &self.upvars),
                         variance,
                     });
                 }
@@ -185,11 +185,11 @@ fn simplify_match_pair<'pat>(
                 is_primary: _,
             } => {
                 if let Ok(place_resolved) =
-                    match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+                    match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
                 {
                     candidate.bindings.push(Binding {
                         span: match_pair.pattern.span,
-                        source: place_resolved.into_place(self.tcx, self.typeck_results),
+                        source: place_resolved.into_place(self.tcx, &self.upvars),
                         var_id: var,
                         binding_mode: mode,
                     });
index 19c303e0bab7400ba0d8e48552ccd0233db9dcc9..47d05a6e32c86a43be1d2c6d691f882ac5c5be95 100644 (file)
@@ -154,10 +154,8 @@ pub(super) fn perform_test(
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
     ) {
         let place: Place<'tcx>;
-        if let Ok(test_place_builder) =
-            place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
-        {
-            place = test_place_builder.into_place(self.tcx, self.typeck_results);
+        if let Ok(test_place_builder) = place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
+            place = test_place_builder.into_place(self.tcx, &self.upvars);
         } else {
             return;
         }
index 06f24040f7be05d80cbd277c2f41dd947cb235d2..b61c4fe50dd3f18886008e399d39ca53b6edf3ec 100644 (file)
@@ -32,13 +32,9 @@ pub(crate) fn prefix_slice_suffix<'pat>(
     ) {
         let tcx = self.tcx;
         let (min_length, exact_size) = if let Ok(place_resolved) =
-            place.clone().try_upvars_resolved(tcx, self.typeck_results)
+            place.clone().try_upvars_resolved(tcx, &self.upvars)
         {
-            match place_resolved
-                .into_place(tcx, self.typeck_results)
-                .ty(&self.local_decls, tcx)
-                .ty
-                .kind()
+            match place_resolved.into_place(tcx, &self.upvars).ty(&self.local_decls, tcx).ty.kind()
             {
                 ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
                 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
index 7f992c18a18e4ce7bd3f87cb1090e13d0bc8f0a1..7d41969a314b69c0dd981062e6d832dbe2c72c07 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -415,12 +416,21 @@ struct Builder<'a, 'tcx> {
     var_indices: FxHashMap<LocalVarId, LocalsForNode>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
-    upvar_mutbls: Vec<Mutability>,
+    upvars: CaptureMap<'tcx>,
     unit_temp: Option<Place<'tcx>>,
 
     var_debug_info: Vec<VarDebugInfo<'tcx>>,
 }
 
+type CaptureMap<'tcx> = SortedIndexMultiMap<usize, hir::HirId, Capture<'tcx>>;
+
+#[derive(Debug)]
+struct Capture<'tcx> {
+    captured_place: &'tcx ty::CapturedPlace<'tcx>,
+    use_place: Place<'tcx>,
+    mutability: Mutability,
+}
+
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
         self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
@@ -865,7 +875,7 @@ fn new(
             in_scope_unsafe: safety,
             local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
             canonical_user_type_annotations: IndexVec::new(),
-            upvar_mutbls: vec![],
+            upvars: CaptureMap::new(),
             var_indices: Default::default(),
             unit_temp: None,
             var_debug_info: vec![],
@@ -934,7 +944,7 @@ fn args_and_body(
         // indexed closure and we stored in a map called closure_min_captures in TypeckResults
         // with the closure's DefId. Here, we run through that vec of UpvarIds for
         // the given closure and use the necessary information to create upvar
-        // debuginfo and to fill `self.upvar_mutbls`.
+        // debuginfo and to fill `self.upvars`.
         if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
             let mut closure_env_projs = vec![];
             let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
@@ -954,7 +964,7 @@ fn args_and_body(
                 .closure_min_captures_flattened(fn_def_id)
                 .zip(capture_tys.zip(capture_syms));
 
-            self.upvar_mutbls = captures_with_tys
+            self.upvars = captures_with_tys
                 .enumerate()
                 .map(|(i, (captured_place, (ty, sym)))| {
                     let capture = captured_place.info.capture_kind;
@@ -974,16 +984,18 @@ fn args_and_body(
                         }
                     };
 
+                    let use_place = Place {
+                        local: ty::CAPTURE_STRUCT_LOCAL,
+                        projection: tcx.intern_place_elems(&projs),
+                    };
                     self.var_debug_info.push(VarDebugInfo {
                         name: *sym,
                         source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
-                        value: VarDebugInfoContents::Place(Place {
-                            local: ty::CAPTURE_STRUCT_LOCAL,
-                            projection: tcx.intern_place_elems(&projs),
-                        }),
+                        value: VarDebugInfoContents::Place(use_place),
                     });
 
-                    mutability
+                    let capture = Capture { captured_place, use_place, mutability };
+                    (var_id, capture)
                 })
                 .collect();
         }