diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index b5dad5ccdea8e..02935af8314f0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -706,13 +706,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         &origin_projection,
                     ) {
                         match captured_place.info.capture_kind {
-                            ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                                kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                                ..
-                            }) => {
+                            ty::UpvarCapture::ByRef(
+                                ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                            ) => {
                                 capture_reason = format!("mutable borrow of `{}`", upvar);
                             }
-                            ty::UpvarCapture::ByValue(_) => {
+                            ty::UpvarCapture::ByValue => {
                                 capture_reason = format!("possible mutation of `{}`", upvar);
                             }
                             _ => bug!("upvar `{}` borrowed, but not mutably", upvar),
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index fe34d6e7ca9dd..7e961e1e750be 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -186,7 +186,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         .map(|captured_place| {
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
-                ty::UpvarCapture::ByValue(_) => false,
+                ty::UpvarCapture::ByValue => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
             Upvar { place: captured_place.clone(), by_ref }
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 771acc2964913..9c2f0ca061a7f 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -52,35 +52,18 @@ impl UpvarId {
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub enum UpvarCapture<'tcx> {
+pub enum UpvarCapture {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
     /// depending on inference.
-    ///
-    /// If the upvar was inferred to be captured by value (e.g. `move`
-    /// was not used), then the `Span` points to a usage that
-    /// required it. There may be more than one such usage
-    /// (e.g. `|| { a; a; }`), in which case we pick an
-    /// arbitrary one.
-    ByValue(Option<Span>),
+    ByValue,
 
     /// Upvar is captured by reference.
-    ByRef(UpvarBorrow<'tcx>),
-}
-
-#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct UpvarBorrow<'tcx> {
-    /// The kind of borrow: by-ref upvars have access to shared
-    /// immutable borrows, which are not part of the normal language
-    /// syntax.
-    pub kind: BorrowKind,
-
-    /// Region of the resulting reference.
-    pub region: ty::Region<'tcx>,
+    ByRef(BorrowKind),
 }
 
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
-pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
+pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
 
 /// Given the closure DefId this map provides a map of root variables to minimum
 /// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
@@ -150,10 +133,13 @@ pub struct CapturedPlace<'tcx> {
     pub place: HirPlace<'tcx>,
 
     /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
-    pub info: CaptureInfo<'tcx>,
+    pub info: CaptureInfo,
 
     /// Represents if `place` can be mutated or not.
     pub mutability: hir::Mutability,
+
+    /// Region of the resulting reference if the upvar is captured by ref.
+    pub region: Option<ty::Region<'tcx>>,
 }
 
 impl<'tcx> CapturedPlace<'tcx> {
@@ -287,7 +273,7 @@ pub fn is_ancestor_or_same_capture(
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct CaptureInfo<'tcx> {
+pub struct CaptureInfo {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
     ///
     /// Eg:
@@ -325,7 +311,7 @@ pub struct CaptureInfo<'tcx> {
     pub path_expr_id: Option<hir::HirId>,
 
     /// Capture mode that was selected
-    pub capture_kind: UpvarCapture<'tcx>,
+    pub capture_kind: UpvarCapture,
 }
 
 pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 78ccfbd5e8cdc..d61554b29ac4b 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -56,8 +56,8 @@ pub use self::binding::BindingMode::*;
 pub use self::closure::{
     is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
     CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList,
-    RootVariableMinCaptureList, UpvarBorrow, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap,
-    UpvarPath, CAPTURE_STRUCT_LOCAL,
+    RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
+    CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree};
 pub use self::context::{
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 98b1a8b4d7631..bb8c2b180e40e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -47,12 +47,6 @@ impl fmt::Debug for ty::UpvarId {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths(|| fmt::Display::fmt(self, f))
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 c6a34ece24576..7e1fc21f3ffc3 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -266,7 +266,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
             // 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,
+                ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
             };
 
             let next_projection = capture.place.projections.len();
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index cb94e75997237..a4f3a63e40b60 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -930,7 +930,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let mut projs = closure_env_projs.clone();
                     projs.push(ProjectionElem::Field(Field::new(i), ty));
                     match capture {
-                        ty::UpvarCapture::ByValue(_) => {}
+                        ty::UpvarCapture::ByValue => {}
                         ty::UpvarCapture::ByRef(..) => {
                             projs.push(ProjectionElem::Deref);
                         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bdde6b4a356c1..c62de1543883e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1108,9 +1108,9 @@ impl<'tcx> Cx<'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
 
         match upvar_capture {
-            ty::UpvarCapture::ByValue(_) => captured_place_expr,
+            ty::UpvarCapture::ByValue => captured_place_expr,
             ty::UpvarCapture::ByRef(upvar_borrow) => {
-                let borrow_kind = match upvar_borrow.kind {
+                let borrow_kind = match upvar_borrow {
                     ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
                     ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
                     ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 9ee305b712f61..2e3bf7ea548ac 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -726,7 +726,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                             );
                             self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
                         }
-                        ty::UpvarCapture::ByValue(_) => {}
+                        ty::UpvarCapture::ByValue => {}
                     }
                 }
             }
@@ -1481,7 +1481,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
         for (&var_hir_id, min_capture_list) in closure_min_captures {
             for captured_place in min_capture_list {
                 match captured_place.info.capture_kind {
-                    ty::UpvarCapture::ByValue(_) => {}
+                    ty::UpvarCapture::ByValue => {}
                     ty::UpvarCapture::ByRef(..) => continue,
                 };
                 let span = captured_place.get_capture_kind_span(self.ir.tcx);
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 1b42edc83be20..0c2f40733505d 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -859,15 +859,15 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
                     self.sub_regions(
                         infer::ReborrowUpvar(span, upvar_id),
                         borrow_region,
-                        upvar_borrow.region,
+                        captured_place.region.unwrap(),
                     );
-                    if let ty::ImmBorrow = upvar_borrow.kind {
+                    if let ty::ImmBorrow = upvar_borrow {
                         debug!("link_upvar_region: capture by shared ref");
                     } else {
                         all_captures_are_imm_borrow = false;
                     }
                 }
-                ty::UpvarCapture::ByValue(_) => {
+                ty::UpvarCapture::ByValue => {
                     all_captures_are_imm_borrow = false;
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index ffd7d29bbbbee..8d3c70b05734f 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -33,7 +33,6 @@
 use super::FnCtxt;
 
 use crate::expr_use_visitor as euv;
-use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -72,7 +71,7 @@ enum PlaceAncestryRelation {
 /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
 /// during capture analysis. Information in this map feeds into the minimum capture
 /// analysis pass.
-type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>;
+type InferredCaptureInformation<'tcx> = Vec<(Place<'tcx>, ty::CaptureInfo)>;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
@@ -207,8 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
         let mut delegate = InferBorrowKind {
             fcx: self,
-            closure_def_id,
-            closure_span: span,
+            closure_def_id: local_def_id,
             capture_information: Default::default(),
             fake_reads: Default::default(),
         };
@@ -231,7 +229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (capture_information, closure_kind, origin) = self
             .process_collected_capture_information(capture_clause, delegate.capture_information);
 
-        self.compute_min_captures(closure_def_id, capture_information);
+        self.compute_min_captures(closure_def_id, capture_information, span);
 
         let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
 
@@ -252,21 +250,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     debug!("seed place {:?}", place);
 
-                    let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
-                    let capture_kind =
-                        self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
+                    let capture_kind = self.init_capture_kind_for_place(&place, capture_clause);
                     let fake_info = ty::CaptureInfo {
                         capture_kind_expr_id: None,
                         path_expr_id: None,
                         capture_kind,
                     };
 
-                    capture_information.insert(place, fake_info);
+                    capture_information.push((place, fake_info));
                 }
             }
 
             // This will update the min captures based on this new fake information.
-            self.compute_min_captures(closure_def_id, capture_information);
+            self.compute_min_captures(closure_def_id, capture_information, span);
         }
 
         let before_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -362,7 +358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     captured_place.place, upvar_ty, capture, captured_place.mutability,
                 );
 
-                apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture)
+                apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
             })
             .collect()
     }
@@ -387,77 +383,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         capture_clause: hir::CaptureBy,
         capture_information: InferredCaptureInformation<'tcx>,
     ) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
-        let mut processed: InferredCaptureInformation<'tcx> = Default::default();
-
         let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
         let mut origin: Option<(Span, Place<'tcx>)> = None;
 
-        for (place, mut capture_info) in capture_information {
-            // Apply rules for safety before inferring closure kind
-            let (place, capture_kind) =
-                restrict_capture_precision(place, capture_info.capture_kind);
-            capture_info.capture_kind = capture_kind;
+        let processed = capture_information
+            .into_iter()
+            .map(|(place, mut capture_info)| {
+                // Apply rules for safety before inferring closure kind
+                let (place, capture_kind) =
+                    restrict_capture_precision(place, capture_info.capture_kind);
 
-            let (place, capture_kind) =
-                truncate_capture_for_optimization(place, capture_info.capture_kind);
-            capture_info.capture_kind = capture_kind;
+                let (place, capture_kind) = truncate_capture_for_optimization(place, capture_kind);
 
-            let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
-                self.tcx.hir().span(usage_expr)
-            } else {
-                unreachable!()
-            };
+                let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
+                    self.tcx.hir().span(usage_expr)
+                } else {
+                    unreachable!()
+                };
 
-            let updated = match capture_info.capture_kind {
-                ty::UpvarCapture::ByValue(..) => match closure_kind {
-                    ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
-                        (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
-                    }
-                    // If closure is already FnOnce, don't update
-                    ty::ClosureKind::FnOnce => (closure_kind, origin),
-                },
+                let updated = match capture_kind {
+                    ty::UpvarCapture::ByValue => match closure_kind {
+                        ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+                            (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
+                        }
+                        // If closure is already FnOnce, don't update
+                        ty::ClosureKind::FnOnce => (closure_kind, origin.take()),
+                    },
 
-                ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                    kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                    ..
-                }) => {
-                    match closure_kind {
-                        ty::ClosureKind::Fn => {
-                            (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+                    ty::UpvarCapture::ByRef(
+                        ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                    ) => {
+                        match closure_kind {
+                            ty::ClosureKind::Fn => {
+                                (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+                            }
+                            // Don't update the origin
+                            ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => {
+                                (closure_kind, origin.take())
+                            }
                         }
-                        // Don't update the origin
-                        ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin),
                     }
-                }
 
-                _ => (closure_kind, origin),
-            };
-
-            closure_kind = updated.0;
-            origin = updated.1;
+                    _ => (closure_kind, origin.take()),
+                };
 
-            let (place, capture_kind) = match capture_clause {
-                hir::CaptureBy::Value => adjust_for_move_closure(place, capture_info.capture_kind),
-                hir::CaptureBy::Ref => {
-                    adjust_for_non_move_closure(place, capture_info.capture_kind)
-                }
-            };
+                closure_kind = updated.0;
+                origin = updated.1;
 
-            // This restriction needs to be applied after we have handled adjustments for `move`
-            // closures. We want to make sure any adjustment that might make us move the place into
-            // the closure gets handled.
-            let (place, capture_kind) =
-                restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+                let (place, capture_kind) = match capture_clause {
+                    hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind),
+                    hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
+                };
 
-            capture_info.capture_kind = capture_kind;
+                // This restriction needs to be applied after we have handled adjustments for `move`
+                // closures. We want to make sure any adjustment that might make us move the place into
+                // the closure gets handled.
+                let (place, capture_kind) =
+                    restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
 
-            let capture_info = if let Some(existing) = processed.get(&place) {
-                determine_capture_info(*existing, capture_info)
-            } else {
-                capture_info
-            };
-            processed.insert(place, capture_info);
-        }
+                capture_info.capture_kind = capture_kind;
+                (place, capture_info)
+            })
+            .collect();
 
         (processed, closure_kind, origin)
     }
@@ -535,6 +522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         closure_def_id: DefId,
         capture_information: InferredCaptureInformation<'tcx>,
+        closure_span: Span,
     ) {
         if capture_information.is_empty() {
             return;
@@ -554,8 +542,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
                     let mutability = self.determine_capture_mutability(&typeck_results, &place);
-                    let min_cap_list =
-                        vec![ty::CapturedPlace { place, info: capture_info, mutability }];
+                    let min_cap_list = vec![ty::CapturedPlace {
+                        place,
+                        info: capture_info,
+                        mutability,
+                        region: None,
+                    }];
                     root_var_min_capture_list.insert(var_hir_id, min_cap_list);
                     continue;
                 }
@@ -608,8 +600,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if !descendant_found {
                 for possible_ancestor in min_cap_list.iter_mut() {
                     match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
+                        PlaceAncestryRelation::SamePlace => {
+                            ancestor_found = true;
+                            possible_ancestor.info = determine_capture_info(
+                                possible_ancestor.info,
+                                updated_capture_info,
+                            );
+
+                            // Only one related place will be in the list.
+                            break;
+                        }
                         // current place is descendant of possible_ancestor
-                        PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
+                        PlaceAncestryRelation::Descendant => {
                             ancestor_found = true;
                             let backup_path_expr_id = possible_ancestor.info.path_expr_id;
 
@@ -629,7 +631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // we need to keep the ancestor's `path_expr_id`
                             possible_ancestor.info.path_expr_id = backup_path_expr_id;
 
-                            // Only one ancestor of the current place will be in the list.
+                            // Only one related place will be in the list.
                             break;
                         }
                         _ => {}
@@ -640,12 +642,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Only need to insert when we don't have an ancestor in the existing min capture list
             if !ancestor_found {
                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
-                let captured_place =
-                    ty::CapturedPlace { place, info: updated_capture_info, mutability };
+                let captured_place = ty::CapturedPlace {
+                    place,
+                    info: updated_capture_info,
+                    mutability,
+                    region: None,
+                };
                 min_cap_list.push(captured_place);
             }
         }
 
+        // For each capture that is determined to be captured by ref, add region info.
+        for (_, captures) in &mut root_var_min_capture_list {
+            for capture in captures {
+                match capture.info.capture_kind {
+                    ty::UpvarCapture::ByRef(_) => {
+                        let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") };
+                        let origin = UpvarRegion(upvar_id, closure_span);
+                        let upvar_region = self.next_region_var(origin);
+                        capture.region = Some(upvar_region);
+                    }
+                    _ => (),
+                }
+            }
+        }
+
         debug!(
             "For closure={:?}, min_captures before sorting={:?}",
             closure_def_id, root_var_min_capture_list
@@ -947,7 +968,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     max_capture_info = determine_capture_info(max_capture_info, capture.info);
                 }
 
-                apply_capture_kind_on_capture_ty(self.tcx, ty, max_capture_info.capture_kind)
+                apply_capture_kind_on_capture_ty(
+                    self.tcx,
+                    ty,
+                    max_capture_info.capture_kind,
+                    Some(&ty::ReErased),
+                )
             }
         };
 
@@ -977,6 +1003,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.tcx,
                 capture.place.ty(),
                 capture.info.capture_kind,
+                Some(&ty::ReErased),
             );
 
             // Checks if a capture implements any of the auto traits
@@ -1086,7 +1113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for captured_place in root_var_min_capture_list.iter() {
             match captured_place.info.capture_kind {
                 // Only care about captures that are moved into the closure
-                ty::UpvarCapture::ByValue(..) => {
+                ty::UpvarCapture::ByValue => {
                     projections_list.push(captured_place.place.projections.as_slice());
                     diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
                         source_expr: captured_place.info.path_expr_id,
@@ -1470,9 +1497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         place: &Place<'tcx>,
         capture_clause: hir::CaptureBy,
-        upvar_id: ty::UpvarId,
-        closure_span: Span,
-    ) -> ty::UpvarCapture<'tcx> {
+    ) -> ty::UpvarCapture {
         match capture_clause {
             // In case of a move closure if the data is accessed through a reference we
             // want to capture by ref to allow precise capture using reborrows.
@@ -1481,14 +1506,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
             // the closure.
             hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
-                ty::UpvarCapture::ByValue(None)
-            }
-            hir::CaptureBy::Value | hir::CaptureBy::Ref => {
-                let origin = UpvarRegion(upvar_id, closure_span);
-                let upvar_region = self.next_region_var(origin);
-                let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
-                ty::UpvarCapture::ByRef(upvar_borrow)
+                ty::UpvarCapture::ByValue
             }
+            hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow),
         }
     }
 
@@ -1513,7 +1533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn log_capture_analysis_first_pass(
         &self,
         closure_def_id: rustc_hir::def_id::DefId,
-        capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
+        capture_information: &InferredCaptureInformation<'tcx>,
         closure_span: Span,
     ) {
         if self.should_log_capture_analysis(closure_def_id) {
@@ -1629,9 +1649,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 fn restrict_repr_packed_field_ref_capture<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    place: &Place<'tcx>,
-    mut curr_borrow_kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut place: Place<'tcx>,
+    mut curr_borrow_kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let pos = place.projections.iter().enumerate().position(|(i, p)| {
         let ty = place.ty_before_projection(i);
 
@@ -1662,8 +1682,6 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
         }
     });
 
-    let mut place = place.clone();
-
     if let Some(pos) = pos {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos);
     }
@@ -1675,12 +1693,14 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
 fn apply_capture_kind_on_capture_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    capture_kind: UpvarCapture<'tcx>,
+    capture_kind: UpvarCapture,
+    region: Option<ty::Region<'tcx>>,
 ) -> Ty<'tcx> {
     match capture_kind {
-        ty::UpvarCapture::ByValue(_) => ty,
-        ty::UpvarCapture::ByRef(borrow) => tcx
-            .mk_ref(borrow.region, ty::TypeAndMut { ty: ty, mutbl: borrow.kind.to_mutbl_lossy() }),
+        ty::UpvarCapture::ByValue => ty,
+        ty::UpvarCapture::ByRef(kind) => {
+            tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() })
+        }
     }
 }
 
@@ -1708,9 +1728,7 @@ struct InferBorrowKind<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
 
     // The def-id of the closure whose kind and upvar accesses are being inferred.
-    closure_def_id: DefId,
-
-    closure_span: Span,
+    closure_def_id: LocalDefId,
 
     /// For each Place that is captured by the closure, we track the minimal kind of
     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -1742,184 +1760,38 @@ struct InferBorrowKind<'a, 'tcx> {
     fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
 }
 
-impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_consume(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        let tcx = self.fcx.tcx;
-        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
-            return;
-        };
-
-        debug!(?upvar_id);
-
-        let usage_span = tcx.hir().span(diag_expr_id);
-
-        let capture_info = ty::CaptureInfo {
-            capture_kind_expr_id: Some(diag_expr_id),
-            path_expr_id: Some(diag_expr_id),
-            capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
-        };
-
-        let curr_info = self.capture_information[&place_with_id.place];
-        let updated_info = determine_capture_info(curr_info, capture_info);
-
-        self.capture_information[&place_with_id.place] = updated_info;
-    }
-
-    /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
-    /// to). If the place is based on a by-ref upvar, this implies that
-    /// the upvar must be borrowed using an `&mut` borrow.
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_mut(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(_) = place_with_id.place.base {
-            // Raw pointers don't inherit mutability
-            if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
-                return;
-            }
-            self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow);
-        }
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_unique(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(_) = place_with_id.place.base {
-            if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
-                // Raw pointers don't inherit mutability.
-                return;
-            }
-            // for a borrowed pointer to be unique, its base must be unique
-            self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow);
-        }
-    }
-
-    fn adjust_upvar_deref(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-        borrow_kind: ty::BorrowKind,
-    ) {
-        assert!(match borrow_kind {
-            ty::MutBorrow => true,
-            ty::UniqueImmBorrow => true,
-
-            // imm borrows never require adjusting any kinds, so we don't wind up here
-            ty::ImmBorrow => false,
-        });
-
-        // if this is an implicit deref of an
-        // upvar, then we need to modify the
-        // borrow_kind of the upvar to make sure it
-        // is inferred to mutable if necessary
-        self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
-    }
-
-    /// We infer the borrow_kind with which to borrow upvars in a stack closure.
-    /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
-    /// moving from left to right as needed (but never right to left).
-    /// Here the argument `mutbl` is the borrow_kind that is required by
-    /// some particular use.
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-        kind: ty::BorrowKind,
-    ) {
-        let curr_capture_info = self.capture_information[&place_with_id.place];
-
-        debug!(?curr_capture_info);
-
-        if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
-            // It's already captured by value, we don't need to do anything here
-            return;
-        } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
-            // Use the same region as the current capture information
-            // Doesn't matter since only one of the UpvarBorrow will be used.
-            let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
-
-            let capture_info = ty::CaptureInfo {
-                capture_kind_expr_id: Some(diag_expr_id),
-                path_expr_id: Some(diag_expr_id),
-                capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
-            };
-            let updated_info = determine_capture_info(curr_capture_info, capture_info);
-            self.capture_information[&place_with_id.place] = updated_info;
-        };
-    }
-
-    #[instrument(skip(self, diag_expr_id), level = "debug")]
-    fn init_capture_info_for_place(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
-            assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
-
-            // Initialize to ImmBorrow
-            // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`.
-            let origin = UpvarRegion(upvar_id, self.closure_span);
-            let upvar_region = self.fcx.next_region_var(origin);
-            let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
-            let capture_kind = ty::UpvarCapture::ByRef(upvar_borrow);
-
-            let expr_id = Some(diag_expr_id);
-            let capture_info = ty::CaptureInfo {
-                capture_kind_expr_id: expr_id,
-                path_expr_id: expr_id,
-                capture_kind,
-            };
-
-            debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
-
-            self.capture_information.insert(place_with_id.place.clone(), capture_info);
-        } else {
-            debug!("Not upvar");
-        }
-    }
-}
-
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
-        if let PlaceBase::Upvar(_) = place.base {
-            // We need to restrict Fake Read precision to avoid fake reading unsafe code,
-            // such as deref of a raw pointer.
-            let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                kind: ty::BorrowKind::ImmBorrow,
-                region: &ty::ReErased,
-            });
+        let PlaceBase::Upvar(_) = place.base else { return };
 
-            let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+        // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+        // such as deref of a raw pointer.
+        let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
 
-            let (place, _) = restrict_repr_packed_field_ref_capture(
-                self.fcx.tcx,
-                self.fcx.param_env,
-                &place,
-                dummy_capture_kind,
-            );
-            self.fake_reads.push((place, cause, diag_expr_id));
-        }
+        let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+
+        let (place, _) = restrict_repr_packed_field_ref_capture(
+            self.fcx.tcx,
+            self.fcx.param_env,
+            place,
+            dummy_capture_kind,
+        );
+        self.fake_reads.push((place, cause, diag_expr_id));
     }
 
     #[instrument(skip(self), level = "debug")]
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
-        if !self.capture_information.contains_key(&place_with_id.place) {
-            self.init_capture_info_for_place(place_with_id, diag_expr_id);
-        }
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
 
-        self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id);
+        self.capture_information.push((
+            place_with_id.place.clone(),
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind: ty::UpvarCapture::ByValue,
+            },
+        ));
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -1929,40 +1801,35 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
         diag_expr_id: hir::HirId,
         bk: ty::BorrowKind,
     ) {
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
+
         // The region here will get discarded/ignored
-        let dummy_capture_kind =
-            ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased });
+        let capture_kind = ty::UpvarCapture::ByRef(bk);
 
         // We only want repr packed restriction to be applied to reading references into a packed
         // struct, and not when the data is being moved. Therefore we call this method here instead
         // of in `restrict_capture_precision`.
-        let (place, updated_kind) = restrict_repr_packed_field_ref_capture(
+        let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
             self.fcx.tcx,
             self.fcx.param_env,
-            &place_with_id.place,
-            dummy_capture_kind,
+            place_with_id.place.clone(),
+            capture_kind,
         );
 
-        let place_with_id = PlaceWithHirId { place, ..*place_with_id };
-
-        if !self.capture_information.contains_key(&place_with_id.place) {
-            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
+        // Raw pointers don't inherit mutability
+        if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+            capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
         }
 
-        match updated_kind {
-            ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, .. }) => match kind {
-                ty::ImmBorrow => {}
-                ty::UniqueImmBorrow => {
-                    self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
-                }
-                ty::MutBorrow => {
-                    self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
-                }
+        self.capture_information.push((
+            place,
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind,
             },
-
-            // Just truncating the place will never cause capture kind to be updated to ByValue
-            ty::UpvarCapture::ByValue(..) => unreachable!(),
-        }
+        ));
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -1975,12 +1842,12 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
 fn restrict_precision_for_drop_types<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
+    mut curr_mode: ty::UpvarCapture,
     span: Span,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
 
-    if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) {
+    if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) {
         for i in 0..place.projections.len() {
             match place.ty_before_projection(i).kind() {
                 ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => {
@@ -2001,8 +1868,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
 /// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
 fn restrict_precision_for_unsafe<'tcx>(
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     if place.base_ty.is_unsafe_ptr() {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
     }
@@ -2034,8 +1901,8 @@ fn restrict_precision_for_unsafe<'tcx>(
 /// Returns the truncated place and updated cature mode.
 fn restrict_capture_precision<'tcx>(
     place: Place<'tcx>,
-    curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
 
     if place.projections.is_empty() {
@@ -2062,30 +1929,28 @@ fn restrict_capture_precision<'tcx>(
 /// Truncate deref of any reference.
 fn adjust_for_move_closure<'tcx>(
     mut place: Place<'tcx>,
-    mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     if let Some(idx) = first_deref {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
     }
 
-    // AMAN: I think we don't need the span inside the ByValue anymore
-    //       we have more detailed span in CaptureInfo
-    (place, ty::UpvarCapture::ByValue(None))
+    (place, ty::UpvarCapture::ByValue)
 }
 
 /// Adjust closure capture just that if taking ownership of data, only move data
 /// from enclosing stack frame.
 fn adjust_for_non_move_closure<'tcx>(
     mut place: Place<'tcx>,
-    mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let contains_deref =
         place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     match kind {
-        ty::UpvarCapture::ByValue(..) => {
+        ty::UpvarCapture::ByValue => {
             if let Some(idx) = contains_deref {
                 truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
             }
@@ -2123,13 +1988,13 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
 fn construct_capture_kind_reason_string<'tcx>(
     tcx: TyCtxt<'_>,
     place: &Place<'tcx>,
-    capture_info: &ty::CaptureInfo<'tcx>,
+    capture_info: &ty::CaptureInfo,
 ) -> String {
     let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
-        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
-        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+        ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
     };
 
     format!("{} captured as {} here", place_str, capture_kind_str)
@@ -2144,13 +2009,13 @@ fn construct_path_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
 fn construct_capture_info_string<'tcx>(
     tcx: TyCtxt<'_>,
     place: &Place<'tcx>,
-    capture_info: &ty::CaptureInfo<'tcx>,
+    capture_info: &ty::CaptureInfo,
 ) -> String {
     let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
-        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
-        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+        ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
     };
     format!("{} -> {}", place_str, capture_kind_str)
 }
@@ -2233,25 +2098,16 @@ fn migration_suggestion_for_2229(
 /// would've already handled `E1`, and have an existing capture_information for it.
 /// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
 /// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
-fn determine_capture_info<'tcx>(
-    capture_info_a: ty::CaptureInfo<'tcx>,
-    capture_info_b: ty::CaptureInfo<'tcx>,
-) -> ty::CaptureInfo<'tcx> {
+fn determine_capture_info(
+    capture_info_a: ty::CaptureInfo,
+    capture_info_b: ty::CaptureInfo,
+) -> ty::CaptureInfo {
     // If the capture kind is equivalent then, we don't need to escalate and can compare the
     // expressions.
     let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-        (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
-            // We don't need to worry about the spans being ignored here.
-            //
-            // The expr_id in capture_info corresponds to the span that is stored within
-            // ByValue(span) and therefore it gets handled with priortizing based on
-            // expressions below.
-            true
-        }
-        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-            ref_a.kind == ref_b.kind
-        }
-        (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
+        (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
+        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
+        (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
     };
 
     if eq_capture_kind {
@@ -2263,10 +2119,10 @@ fn determine_capture_info<'tcx>(
         // We select the CaptureKind which ranks higher based the following priority order:
         // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
         match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-            (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
-            (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
+            (ty::UpvarCapture::ByValue, _) => capture_info_a,
+            (_, ty::UpvarCapture::ByValue) => capture_info_b,
             (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-                match (ref_a.kind, ref_b.kind) {
+                match (ref_a, ref_b) {
                     // Take LHS:
                     (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
                     | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
@@ -2294,7 +2150,7 @@ fn determine_capture_info<'tcx>(
 /// contained `Deref` of `&mut`.
 fn truncate_place_to_len_and_update_capture_kind<'tcx>(
     place: &mut Place<'tcx>,
-    curr_mode: &mut ty::UpvarCapture<'tcx>,
+    curr_mode: &mut ty::UpvarCapture,
     len: usize,
 ) {
     let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut));
@@ -2304,22 +2160,19 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
     // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
     // we don't need to worry about that case here.
     match curr_mode {
-        ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: ty::BorrowKind::MutBorrow, region }) => {
+        ty::UpvarCapture::ByRef(ty::BorrowKind::MutBorrow) => {
             for i in len..place.projections.len() {
                 if place.projections[i].kind == ProjectionKind::Deref
                     && is_mut_ref(place.ty_before_projection(i))
                 {
-                    *curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                        kind: ty::BorrowKind::UniqueImmBorrow,
-                        region,
-                    });
+                    *curr_mode = ty::UpvarCapture::ByRef(ty::BorrowKind::UniqueImmBorrow);
                     break;
                 }
             }
         }
 
         ty::UpvarCapture::ByRef(..) => {}
-        ty::UpvarCapture::ByValue(..) => {}
+        ty::UpvarCapture::ByValue => {}
     }
 
     place.projections.truncate(len);
@@ -2390,8 +2243,8 @@ fn determine_place_ancestry_relation<'tcx>(
 /// ```
 fn truncate_capture_for_optimization<'tcx>(
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
 
     // Find the right-most deref (if any). All the projections that come after this
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 1ae0ff3036471..352cdefc0b47b 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -796,14 +796,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     );
 
                     match capture_info.capture_kind {
-                        ty::UpvarCapture::ByValue(_) => {
+                        ty::UpvarCapture::ByValue => {
                             self.delegate_consume(&place_with_id, place_with_id.hir_id);
                         }
                         ty::UpvarCapture::ByRef(upvar_borrow) => {
                             self.delegate.borrow(
                                 &place_with_id,
                                 place_with_id.hir_id,
-                                upvar_borrow.kind,
+                                upvar_borrow,
                             );
                         }
                     }
diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs
index 7a4b21f022365..2bcbd792e3a83 100644
--- a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs
+++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs
@@ -15,6 +15,7 @@ fn main() {
         //~^ NOTE: Capturing m[] -> MutBorrow
         //~| NOTE: Min Capture m[] -> MutBorrow
         m[1] += 40;
+        //~^ NOTE: Capturing m[] -> MutBorrow
     };
 
     c();
diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr
index 69ec53447b8a6..129b26456ce1d 100644
--- a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr
@@ -15,7 +15,7 @@ LL | |
 LL | |
 LL | |         m[0] += 10;
 ...  |
-LL | |         m[1] += 40;
+LL | |
 LL | |     };
    | |_____^
    |
@@ -24,6 +24,11 @@ note: Capturing m[] -> MutBorrow
    |
 LL |         m[0] += 10;
    |         ^
+note: Capturing m[] -> MutBorrow
+  --> $DIR/arrays-completely-captured.rs:17:9
+   |
+LL |         m[1] += 40;
+   |         ^
 
 error: Min Capture analysis includes:
   --> $DIR/arrays-completely-captured.rs:11:5
@@ -33,7 +38,7 @@ LL | |
 LL | |
 LL | |         m[0] += 10;
 ...  |
-LL | |         m[1] += 40;
+LL | |
 LL | |     };
    | |_____^
    |
diff --git a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs
index 9918802334ecc..6c65a7bf87b96 100644
--- a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs
+++ b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs
@@ -15,6 +15,8 @@ fn arrays() {
     //~| ERROR: Min Capture analysis includes:
         let [a, b, .., e] = arr;
         //~^ NOTE: Capturing arr[Index] -> ByValue
+        //~| NOTE: Capturing arr[Index] -> ByValue
+        //~| NOTE: Capturing arr[Index] -> ByValue
         //~| NOTE: Min Capture arr[] -> ByValue
         assert_eq!(a, "A");
         assert_eq!(b, "B");
diff --git a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr
index b53adb5248161..44fbe6d8158f2 100644
--- a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr
@@ -8,7 +8,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/destructure_patterns.rs:36:13
+  --> $DIR/destructure_patterns.rs:38:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/destructure_patterns.rs:56:13
+  --> $DIR/destructure_patterns.rs:58:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,6 +42,16 @@ note: Capturing arr[Index] -> ByValue
    |
 LL |         let [a, b, .., e] = arr;
    |                             ^^^
+note: Capturing arr[Index] -> ByValue
+  --> $DIR/destructure_patterns.rs:16:29
+   |
+LL |         let [a, b, .., e] = arr;
+   |                             ^^^
+note: Capturing arr[Index] -> ByValue
+  --> $DIR/destructure_patterns.rs:16:29
+   |
+LL |         let [a, b, .., e] = arr;
+   |                             ^^^
 
 error: Min Capture analysis includes:
   --> $DIR/destructure_patterns.rs:13:5
@@ -62,7 +72,7 @@ LL |         let [a, b, .., e] = arr;
    |                             ^^^
 
 error: First Pass analysis includes:
-  --> $DIR/destructure_patterns.rs:39:5
+  --> $DIR/destructure_patterns.rs:41:5
    |
 LL | /     || {
 LL | |
@@ -74,18 +84,18 @@ LL | |     };
    | |_____^
    |
 note: Capturing p[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 note: Capturing p[(2, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 
 error: Min Capture analysis includes:
-  --> $DIR/destructure_patterns.rs:39:5
+  --> $DIR/destructure_patterns.rs:41:5
    |
 LL | /     || {
 LL | |
@@ -97,18 +107,18 @@ LL | |     };
    | |_____^
    |
 note: Min Capture p[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 note: Min Capture p[(2, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 
 error: First Pass analysis includes:
-  --> $DIR/destructure_patterns.rs:59:5
+  --> $DIR/destructure_patterns.rs:61:5
    |
 LL | /     || {
 LL | |
@@ -120,23 +130,23 @@ LL | |     };
    | |_____^
    |
 note: Capturing t[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Capturing t[(1, 0)] -> ImmBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Capturing t[(2, 0),(0, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 
 error: Min Capture analysis includes:
-  --> $DIR/destructure_patterns.rs:59:5
+  --> $DIR/destructure_patterns.rs:61:5
    |
 LL | /     || {
 LL | |
@@ -148,17 +158,17 @@ LL | |     };
    | |_____^
    |
 note: Min Capture t[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Min Capture t[(1, 0)] -> ImmBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Min Capture t[(2, 0),(0, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs
new file mode 100644
index 0000000000000..46b54846e32eb
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs
@@ -0,0 +1,25 @@
+// edition:2021
+
+// Test that we point to the correct location that results a union being captured.
+// Union is special because it can't be disjointly captured.
+
+union A {
+    y: u32,
+    x: (),
+}
+
+fn main() {
+    let mut a = A { y: 1 };
+    let mut c = || {
+    //~^ borrow of `a.y` occurs here
+        let _ = unsafe { &a.y };
+        let _ = &mut a;
+        //~^ borrow occurs due to use in closure
+        let _ = unsafe { &mut a.y };
+    };
+    a.y = 1;
+    //~^ cannot assign to `a.y` because it is borrowed [E0506]
+    //~| assignment to borrowed `a.y` occurs here
+    c();
+    //~^ borrow later used here
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr
new file mode 100644
index 0000000000000..7c34e2336c867
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `a.y` because it is borrowed
+  --> $DIR/union.rs:20:5
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `a.y` occurs here
+...
+LL |         let _ = &mut a;
+   |                      - borrow occurs due to use in closure
+...
+LL |     a.y = 1;
+   |     ^^^^^^^ assignment to borrowed `a.y` occurs here
+...
+LL |     c();
+   |     - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs
index f6775b3a3a5ac..22eae744b8080 100644
--- a/src/test/ui/closures/2229_closure_analysis/nested-closure.rs
+++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs
@@ -40,6 +40,7 @@ fn main() {
         //~| NOTE: Min Capture p[(1, 0)] -> MutBorrow
         c2();
         println!("{}", p.y);
+        //~^ NOTE: Capturing p[(1, 0)] -> ImmBorrow
     };
 
     c1();
diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr
index 013bc74e67e1e..a50d0c6a182bc 100644
--- a/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr
@@ -58,7 +58,7 @@ LL | |
 LL | |
 LL | |         println!("{}", p.x);
 ...  |
-LL | |         println!("{}", p.y);
+LL | |
 LL | |     };
    | |_____^
    |
@@ -72,6 +72,11 @@ note: Capturing p[(1, 0)] -> MutBorrow
    |
 LL |         || p.y += incr;
    |            ^^^
+note: Capturing p[(1, 0)] -> ImmBorrow
+  --> $DIR/nested-closure.rs:42:24
+   |
+LL |         println!("{}", p.y);
+   |                        ^^^
 
 error: Min Capture analysis includes:
   --> $DIR/nested-closure.rs:22:5
@@ -81,7 +86,7 @@ LL | |
 LL | |
 LL | |         println!("{}", p.x);
 ...  |
-LL | |         println!("{}", p.y);
+LL | |
 LL | |     };
    | |_____^
    |
diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
index 7d472ad020f29..3ed780f51c73b 100644
--- a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
+++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
@@ -48,6 +48,7 @@ fn test_alignment_affected() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         let z1: &String = &foo.x;
+        //~^ NOTE: Capturing foo[] -> ImmBorrow
         let z2: &mut u16 = &mut foo.y;
         //~^ NOTE: Capturing foo[] -> MutBorrow
         //~| NOTE: Min Capture foo[] -> MutBorrow
diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
index 405f66210aa55..580061ebc6ed9 100644
--- a/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
@@ -17,7 +17,7 @@ LL |     let mut c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/repr_packed.rs:78:13
+  --> $DIR/repr_packed.rs:79:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,8 +83,13 @@ LL | |         println!("({}, {})", z1, z2);
 LL | |     };
    | |_____^
    |
+note: Capturing foo[] -> ImmBorrow
+  --> $DIR/repr_packed.rs:50:28
+   |
+LL |         let z1: &String = &foo.x;
+   |                            ^^^^^
 note: Capturing foo[] -> MutBorrow
-  --> $DIR/repr_packed.rs:51:33
+  --> $DIR/repr_packed.rs:52:33
    |
 LL |         let z2: &mut u16 = &mut foo.y;
    |                                 ^^^^^
@@ -102,13 +107,13 @@ LL | |     };
    | |_____^
    |
 note: Min Capture foo[] -> MutBorrow
-  --> $DIR/repr_packed.rs:51:33
+  --> $DIR/repr_packed.rs:52:33
    |
 LL |         let z2: &mut u16 = &mut foo.y;
    |                                 ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/repr_packed.rs:81:5
+  --> $DIR/repr_packed.rs:82:5
    |
 LL | /     || {
 LL | |
@@ -120,18 +125,18 @@ LL | |     };
    | |_____^
    |
 note: Capturing foo[] -> ImmBorrow
-  --> $DIR/repr_packed.rs:84:24
+  --> $DIR/repr_packed.rs:85:24
    |
 LL |         println!("{}", foo.x);
    |                        ^^^^^
 note: Capturing foo[(0, 0)] -> ByValue
-  --> $DIR/repr_packed.rs:88:18
+  --> $DIR/repr_packed.rs:89:18
    |
 LL |         let _z = foo.x;
    |                  ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/repr_packed.rs:81:5
+  --> $DIR/repr_packed.rs:82:5
    |
 LL | /     || {
 LL | |
@@ -143,7 +148,7 @@ LL | |     };
    | |_____^
    |
 note: Min Capture foo[] -> ByValue
-  --> $DIR/repr_packed.rs:84:24
+  --> $DIR/repr_packed.rs:85:24
    |
 LL |         println!("{}", foo.x);
    |                        ^^^^^ foo[] used here
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9179e67c4f4ee..2a06cf121ff01 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -969,8 +969,8 @@ pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) ->
                         };
                         if !self.locals.contains(&local_id) {
                             let capture = match capture.info.capture_kind {
-                                UpvarCapture::ByValue(_) => CaptureKind::Value,
-                                UpvarCapture::ByRef(borrow) => match borrow.kind {
+                                UpvarCapture::ByValue => CaptureKind::Value,
+                                UpvarCapture::ByRef(kind) => match kind {
                                     BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
                                     BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
                                         CaptureKind::Ref(Mutability::Mut)