Skip to main content

rustc_borrowck/
borrow_set.rs

1use std::collections::hash_map::Entry;
2use std::fmt;
3use std::ops::Index;
4
5use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
6use rustc_hir::Mutability;
7use rustc_index::IndexVec;
8use rustc_index::bit_set::DenseBitSet;
9use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
10use rustc_middle::mir::{self, Body, Local, Location, traversal};
11use rustc_middle::ty::data_structures::IndexSet;
12use rustc_middle::ty::{RegionVid, TyCtxt};
13use rustc_middle::{bug, span_bug, ty};
14use rustc_mir_dataflow::move_paths::MoveData;
15use smallvec::{SmallVec, smallvec};
16use tracing::debug;
17
18use crate::BorrowIndex;
19use crate::place_ext::PlaceExt;
20
21pub struct BorrowSet<'tcx> {
22    /// BorrowData storage.
23    borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
24
25    /// The fundamental map relating bitvector indexes to the borrows
26    /// in the MIR. Each borrow of a reference is uniquely identified in the MIR
27    /// by the `Location` of the assignment statement in which it
28    /// appears on the right hand side, but for generic Reborrow there may be
29    /// multiple borrows per location. Thus the location is the map
30    /// key, and it identifies one or more `BorrowIndex` values.
31    ///
32    /// FIXME(reborrow): if the Reborrow experiment is rejected, this can be turned
33    /// back into a FxIndexMap<Location, BorrowData<'tcx> or BorrowIndex>. See [PR].
34    ///
35    /// [PR]: github.com/rust-lang/rust/pull/159449
36    location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
37
38    /// Locations which activate borrows.
39    activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
40
41    /// Map from local to all the borrows on that local.
42    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
43
44    locals_state_at_exit: LocalsStateAtExit,
45}
46
47impl<'tcx> BorrowSet<'tcx> {
48    // Public method to support Aquascope.
49    pub fn build(
50        tcx: TyCtxt<'tcx>,
51        body: &Body<'tcx>,
52        locals_are_invalidated_at_exit: bool,
53        move_data: &MoveData<'tcx>,
54    ) -> Self {
55        let mut visitor = GatherBorrows {
56            tcx,
57            body,
58            borrows: Default::default(),
59            location_map: Default::default(),
60            activation_map: Default::default(),
61            local_map: Default::default(),
62            pending_activations: Default::default(),
63            locals_state_at_exit: LocalsStateAtExit::build(
64                locals_are_invalidated_at_exit,
65                body,
66                move_data,
67            ),
68        };
69
70        for (block, block_data) in traversal::preorder(body) {
71            visitor.visit_basic_block_data(block, block_data);
72        }
73
74        BorrowSet {
75            borrows: visitor.borrows,
76            location_map: visitor.location_map,
77            activation_map: visitor.activation_map,
78            local_map: visitor.local_map,
79            locals_state_at_exit: visitor.locals_state_at_exit,
80        }
81    }
82
83    // Public method to support Aquascope.
84    /// Iterate through all BorrowData in the BorrowSet.
85    pub fn iter(&self) -> impl Iterator<Item = &BorrowData<'tcx>> {
86        self.borrows.iter()
87    }
88
89    // The following functions are not depended upon by outside consumers.
90    pub(crate) fn locals_state_at_exit(&self) -> &LocalsStateAtExit {
91        &self.locals_state_at_exit
92    }
93
94    pub(crate) fn len(&self) -> usize {
95        self.borrows.len()
96    }
97
98    pub(crate) fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
99        self.borrows.iter_enumerated()
100    }
101
102    pub(crate) fn activations_at_location(&self, location: &Location) -> &[BorrowIndex] {
103        self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
104    }
105
106    pub(crate) fn borrows_at_location(&self, location: &Location) -> Option<&[BorrowIndex]> {
107        self.location_map.get(location).map(|v| v.as_slice())
108    }
109
110    pub(crate) fn borrows_on_local(&self, local: Local) -> Option<&IndexSet<BorrowIndex>> {
111        self.local_map.get(&local)
112    }
113}
114
115impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
116    type Output = BorrowData<'tcx>;
117
118    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
119        &self.borrows[index]
120    }
121}
122
123/// Location where a two-phase borrow is activated, if a borrow
124/// is in fact a two-phase borrow.
125#[derive(#[automatically_derived]
impl ::core::marker::Copy for TwoPhaseActivation { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TwoPhaseActivation {
    #[inline]
    fn clone(&self) -> TwoPhaseActivation {
        let _: ::core::clone::AssertParamIsClone<Location>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for TwoPhaseActivation {
    #[inline]
    fn eq(&self, other: &TwoPhaseActivation) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (TwoPhaseActivation::ActivatedAt(__self_0),
                    TwoPhaseActivation::ActivatedAt(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TwoPhaseActivation {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Location>;
    }
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for TwoPhaseActivation {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TwoPhaseActivation::NotTwoPhase =>
                ::core::fmt::Formatter::write_str(f, "NotTwoPhase"),
            TwoPhaseActivation::NotActivated =>
                ::core::fmt::Formatter::write_str(f, "NotActivated"),
            TwoPhaseActivation::ActivatedAt(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ActivatedAt", &__self_0),
        }
    }
}Debug)]
126pub enum TwoPhaseActivation {
127    NotTwoPhase,
128    NotActivated,
129    ActivatedAt(Location),
130}
131
132#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for BorrowData<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["reserve_location", "activation_location", "kind", "region",
                        "borrowed_place", "assigned_place"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.reserve_location, &self.activation_location, &self.kind,
                        &self.region, &self.borrowed_place, &&self.assigned_place];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "BorrowData",
            names, values)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for BorrowData<'tcx> {
    #[inline]
    fn clone(&self) -> BorrowData<'tcx> {
        BorrowData {
            reserve_location: ::core::clone::Clone::clone(&self.reserve_location),
            activation_location: ::core::clone::Clone::clone(&self.activation_location),
            kind: ::core::clone::Clone::clone(&self.kind),
            region: ::core::clone::Clone::clone(&self.region),
            borrowed_place: ::core::clone::Clone::clone(&self.borrowed_place),
            assigned_place: ::core::clone::Clone::clone(&self.assigned_place),
        }
    }
}Clone)]
133pub struct BorrowData<'tcx> {
134    /// Location where the borrow reservation starts.
135    /// In many cases, this will be equal to the activation location but not always.
136    pub(crate) reserve_location: Location,
137    /// Location where the borrow is activated.
138    pub(crate) activation_location: TwoPhaseActivation,
139    /// What kind of borrow this is
140    pub(crate) kind: mir::BorrowKind,
141    /// The region for which this borrow is live
142    pub(crate) region: RegionVid,
143    /// Place from which we are borrowing
144    pub(crate) borrowed_place: mir::Place<'tcx>,
145    /// Place to which the borrow was stored
146    pub(crate) assigned_place: mir::Place<'tcx>,
147}
148
149// These methods are public to support borrowck consumers.
150impl<'tcx> BorrowData<'tcx> {
151    pub fn reserve_location(&self) -> Location {
152        self.reserve_location
153    }
154
155    pub fn activation_location(&self) -> TwoPhaseActivation {
156        self.activation_location
157    }
158
159    pub fn kind(&self) -> mir::BorrowKind {
160        self.kind
161    }
162
163    pub fn region(&self) -> RegionVid {
164        self.region
165    }
166
167    pub fn borrowed_place(&self) -> mir::Place<'tcx> {
168        self.borrowed_place
169    }
170
171    pub fn assigned_place(&self) -> mir::Place<'tcx> {
172        self.assigned_place
173    }
174}
175
176impl<'tcx> fmt::Display for BorrowData<'tcx> {
177    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
178        let kind = match self.kind {
179            mir::BorrowKind::Shared => "",
180            mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
181            mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
182            mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
183            // FIXME: differentiate `TwoPhaseBorrow`
184            mir::BorrowKind::Mut {
185                kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow,
186            } => "mut ",
187        };
188        w.write_fmt(format_args!("&{0:?} {1}{2:?}", self.region, kind,
        self.borrowed_place))write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
189    }
190}
191
192pub enum LocalsStateAtExit {
193    AllAreInvalidated,
194    SomeAreInvalidated { has_storage_dead_or_moved: DenseBitSet<Local> },
195}
196
197impl LocalsStateAtExit {
198    fn build<'tcx>(
199        locals_are_invalidated_at_exit: bool,
200        body: &Body<'tcx>,
201        move_data: &MoveData<'tcx>,
202    ) -> Self {
203        struct HasStorageDead(DenseBitSet<Local>);
204
205        impl<'tcx> Visitor<'tcx> for HasStorageDead {
206            fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) {
207                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
208                    self.0.insert(local);
209                }
210            }
211        }
212
213        if locals_are_invalidated_at_exit {
214            LocalsStateAtExit::AllAreInvalidated
215        } else {
216            let mut has_storage_dead =
217                HasStorageDead(DenseBitSet::new_empty(body.local_decls.len()));
218            has_storage_dead.visit_body(body);
219            let mut has_storage_dead_or_moved = has_storage_dead.0;
220            for move_out in &move_data.moves {
221                has_storage_dead_or_moved.insert(move_data.base_local(move_out.path));
222            }
223            LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved }
224        }
225    }
226}
227
228struct GatherBorrows<'a, 'tcx> {
229    tcx: TyCtxt<'tcx>,
230    body: &'a Body<'tcx>,
231    borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
232    location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
233    activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
234    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
235
236    /// When we encounter a 2-phase borrow statement, it will always
237    /// be assigning into a temporary TEMP:
238    ///
239    ///    TEMP = &foo
240    ///
241    /// We add TEMP into this map with `b`, where `b` is the index of
242    /// the borrow. When we find a later use of this activation, we
243    /// remove from the map (and add to the "tombstone" set below).
244    pending_activations: FxIndexMap<mir::Local, BorrowIndex>,
245
246    locals_state_at_exit: LocalsStateAtExit,
247}
248
249impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
250    fn insert_borrow(&mut self, location: Location, borrow: BorrowData<'tcx>) -> BorrowIndex {
251        let idx = self.borrows.push(borrow);
252        match self.location_map.entry(location) {
253            Entry::Occupied(entry) => {
254                ::rustc_middle::util::bug::bug_fmt(format_args!("Inserting a borrow {0:?} at {1:?} attempted to override an existing list {2:?}",
        idx, location, entry));bug!(
255                    "Inserting a borrow {idx:?} at {location:?} attempted to override an existing list {entry:?}"
256                );
257            }
258            Entry::Vacant(entry) => {
259                entry.insert({
    let count = 0usize + 1usize;
    let mut vec = ::smallvec::SmallVec::new();
    if count <= vec.inline_size() {
        vec.push(idx);
        vec
    } else {
        ::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                    [idx])))
    }
}smallvec![idx]);
260            }
261        }
262        idx
263    }
264}
265
266impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
267    fn visit_assign(
268        &mut self,
269        assigned_place: &mir::Place<'tcx>,
270        rvalue: &mir::Rvalue<'tcx>,
271        location: mir::Location,
272    ) {
273        if let &mir::Rvalue::Ref(region, kind, borrowed_place) = rvalue {
274            if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
275                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/borrow_set.rs:275",
                        "rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/borrow_set.rs"),
                        ::tracing_core::__macro_support::Option::Some(275u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_borrowck::borrow_set"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("ignoring_borrow of {0:?}",
                                                    borrowed_place) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("ignoring_borrow of {:?}", borrowed_place);
276                return;
277            }
278
279            let region = region.as_var();
280            let borrow = |activation_location| BorrowData {
281                kind,
282                region,
283                reserve_location: location,
284                activation_location,
285                borrowed_place,
286                assigned_place: *assigned_place,
287            };
288
289            let idx = if !kind.is_two_phase_borrow() {
290                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/borrow_set.rs:290",
                        "rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/borrow_set.rs"),
                        ::tracing_core::__macro_support::Option::Some(290u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_borrowck::borrow_set"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("  -> {0:?}",
                                                    location) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("  -> {:?}", location);
291                self.insert_borrow(location, borrow(TwoPhaseActivation::NotTwoPhase))
292            } else {
293                // When we encounter a 2-phase borrow statement, it will always
294                // be assigning into a temporary TEMP:
295                //
296                //    TEMP = &foo
297                //
298                // so extract `temp`.
299                let Some(temp) = assigned_place.as_local() else {
300                    ::rustc_middle::util::bug::span_bug_fmt(self.body.source_info(location).span,
    format_args!("expected 2-phase borrow to assign to a local, not `{0:?}`",
        assigned_place));span_bug!(
301                        self.body.source_info(location).span,
302                        "expected 2-phase borrow to assign to a local, not `{:?}`",
303                        assigned_place,
304                    );
305                };
306
307                // Consider the borrow not activated to start. When we find an activation, we'll update
308                // this field.
309                let idx = self.insert_borrow(location, borrow(TwoPhaseActivation::NotActivated));
310
311                // Insert `temp` into the list of pending activations. From
312                // now on, we'll be on the lookout for a use of it. Note that
313                // we are guaranteed that this use will come after the
314                // assignment.
315                let prev = self.pending_activations.insert(temp, idx);
316                {
    match (&prev, &None) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val,
                    ::core::option::Option::Some(format_args!("temporary associated with multiple two phase borrows")));
            }
        }
    }
};assert_eq!(prev, None, "temporary associated with multiple two phase borrows");
317
318                idx
319            };
320
321            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
322        } else if let &mir::Rvalue::Reborrow(target, mutability, borrowed_place) = rvalue {
323            let borrowed_place_ty = borrowed_place.ty(self.body, self.tcx).ty;
324            let &ty::Adt(reborrowed_adt, _reborrowed_args) = borrowed_place_ty.kind() else {
325                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
326            };
327            let &ty::Adt(target_adt, assigned_args) = target.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
328            let Some(ty::GenericArgKind::Lifetime(region)) = assigned_args.get(0).map(|r| r.kind())
329            else {
330                ::rustc_middle::util::bug::bug_fmt(format_args!("hir-typeck passed but {0} does not have a lifetime argument",
        if mutability == Mutability::Mut {
            "Reborrow"
        } else { "CoerceShared" }));bug!(
331                    "hir-typeck passed but {} does not have a lifetime argument",
332                    if mutability == Mutability::Mut { "Reborrow" } else { "CoerceShared" }
333                );
334            };
335            let region = region.as_var();
336            let kind = if mutability == Mutability::Mut {
337                // Reborrow
338                if target_adt.did() != reborrowed_adt.did() {
339                    ::rustc_middle::util::bug::bug_fmt(format_args!("hir-typeck passed but Reborrow involves mismatching types at {0:?}",
        location))bug!(
340                        "hir-typeck passed but Reborrow involves mismatching types at {location:?}"
341                    )
342                }
343
344                mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
345            } else {
346                // CoerceShared
347                if target_adt.did() == reborrowed_adt.did() {
348                    ::rustc_middle::util::bug::bug_fmt(format_args!("hir-typeck passed but CoerceShared involves matching types at {0:?}",
        location))bug!(
349                        "hir-typeck passed but CoerceShared involves matching types at {location:?}"
350                    )
351                }
352                mir::BorrowKind::Shared
353            };
354            let borrow = BorrowData {
355                kind,
356                region,
357                reserve_location: location,
358                activation_location: TwoPhaseActivation::NotTwoPhase,
359                borrowed_place,
360                assigned_place: *assigned_place,
361            };
362            let idx = self.insert_borrow(location, borrow);
363
364            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
365        }
366
367        self.super_assign(assigned_place, rvalue, location)
368    }
369
370    fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) {
371        if !context.is_use() {
372            return;
373        }
374
375        // We found a use of some temporary TMP
376        // check whether we (earlier) saw a 2-phase borrow like
377        //
378        //     TMP = &mut place
379        let Some(&borrow_index) = self.pending_activations.get(&temp) else {
380            return;
381        };
382        let borrow_data = &mut self.borrows[borrow_index];
383
384        // Watch out: the use of TMP in the borrow itself
385        // doesn't count as an activation. =)
386        if borrow_data.reserve_location == location
387            && context == PlaceContext::MutatingUse(MutatingUseContext::Store)
388        {
389            return;
390        }
391
392        if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location {
393            ::rustc_middle::util::bug::span_bug_fmt(self.body.source_info(location).span,
    format_args!("found two uses for 2-phase borrow temporary {0:?}: {1:?} and {2:?}",
        temp, location, other_location));span_bug!(
394                self.body.source_info(location).span,
395                "found two uses for 2-phase borrow temporary {:?}: \
396                {:?} and {:?}",
397                temp,
398                location,
399                other_location,
400            );
401        }
402
403        // Otherwise, this is the unique later use that we expect.
404        // Double check: This borrow is indeed a two-phase borrow (that is,
405        // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
406        // we've not found any other activations (checked above).
407        {
    match (&borrow_data.activation_location,
            &TwoPhaseActivation::NotActivated) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val,
                    ::core::option::Option::Some(format_args!("never found an activation for this borrow!")));
            }
        }
    }
};assert_eq!(
408            borrow_data.activation_location,
409            TwoPhaseActivation::NotActivated,
410            "never found an activation for this borrow!",
411        );
412        self.activation_map.entry(location).or_default().push(borrow_index);
413
414        borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
415    }
416
417    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
418        if let &mir::Rvalue::Ref(region, kind, place) = rvalue {
419            // double-check that we already registered a BorrowData for this
420
421            let idxs = &self.location_map[&location];
422            for idx in idxs {
423                let borrow_data = &self.borrows[*idx];
424                {
    match (&borrow_data.reserve_location, &location) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(borrow_data.reserve_location, location);
425                {
    match (&borrow_data.kind, &kind) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(borrow_data.kind, kind);
426                {
    match (&borrow_data.region, &region.as_var()) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(borrow_data.region, region.as_var());
427                {
    match (&borrow_data.borrowed_place, &place) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(borrow_data.borrowed_place, place);
428            }
429        }
430
431        self.super_rvalue(rvalue, location)
432    }
433}