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 and Creusot.
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    // Public method to support Creusot.
90    pub fn locals_state_at_exit(&self) -> &LocalsStateAtExit {
91        &self.locals_state_at_exit
92    }
93
94    // Public method to support Creusot.
95    pub fn len(&self) -> usize {
96        self.borrows.len()
97    }
98
99    pub fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
100        self.borrows.iter_enumerated()
101    }
102
103    // Public method to support Creusot.
104    pub fn activations_at_location(&self, location: &Location) -> &[BorrowIndex] {
105        self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
106    }
107
108    // Public method to support Creusot.
109    pub fn borrows_at_location(&self, location: &Location) -> Option<&[BorrowIndex]> {
110        self.location_map.get(location).map(|v| v.as_slice())
111    }
112
113    // Public method to support Creusot.
114    pub fn borrows_on_local(&self, local: Local) -> Option<&IndexSet<BorrowIndex>> {
115        self.local_map.get(&local)
116    }
117}
118
119impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
120    type Output = BorrowData<'tcx>;
121
122    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
123        &self.borrows[index]
124    }
125}
126
127/// Location where a two-phase borrow is activated, if a borrow
128/// is in fact a two-phase borrow.
129#[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)]
130pub enum TwoPhaseActivation {
131    NotTwoPhase,
132    NotActivated,
133    ActivatedAt(Location),
134}
135
136#[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)]
137pub struct BorrowData<'tcx> {
138    /// Location where the borrow reservation starts.
139    /// In many cases, this will be equal to the activation location but not always.
140    pub(crate) reserve_location: Location,
141    /// Location where the borrow is activated.
142    pub(crate) activation_location: TwoPhaseActivation,
143    /// What kind of borrow this is
144    pub(crate) kind: mir::BorrowKind,
145    /// The region for which this borrow is live
146    pub(crate) region: RegionVid,
147    /// Place from which we are borrowing
148    pub(crate) borrowed_place: mir::Place<'tcx>,
149    /// Place to which the borrow was stored
150    pub(crate) assigned_place: mir::Place<'tcx>,
151}
152
153// These methods are public to support borrowck consumers.
154impl<'tcx> BorrowData<'tcx> {
155    pub fn reserve_location(&self) -> Location {
156        self.reserve_location
157    }
158
159    pub fn activation_location(&self) -> TwoPhaseActivation {
160        self.activation_location
161    }
162
163    pub fn kind(&self) -> mir::BorrowKind {
164        self.kind
165    }
166
167    pub fn region(&self) -> RegionVid {
168        self.region
169    }
170
171    pub fn borrowed_place(&self) -> mir::Place<'tcx> {
172        self.borrowed_place
173    }
174
175    pub fn assigned_place(&self) -> mir::Place<'tcx> {
176        self.assigned_place
177    }
178}
179
180impl<'tcx> fmt::Display for BorrowData<'tcx> {
181    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
182        let kind = match self.kind {
183            mir::BorrowKind::Shared => "",
184            mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
185            mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
186            mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
187            // FIXME: differentiate `TwoPhaseBorrow`
188            mir::BorrowKind::Mut {
189                kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow,
190            } => "mut ",
191        };
192        w.write_fmt(format_args!("&{0:?} {1}{2:?}", self.region, kind,
        self.borrowed_place))write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
193    }
194}
195
196pub enum LocalsStateAtExit {
197    AllAreInvalidated,
198    SomeAreInvalidated { has_storage_dead_or_moved: DenseBitSet<Local> },
199}
200
201impl LocalsStateAtExit {
202    fn build<'tcx>(
203        locals_are_invalidated_at_exit: bool,
204        body: &Body<'tcx>,
205        move_data: &MoveData<'tcx>,
206    ) -> Self {
207        struct HasStorageDead(DenseBitSet<Local>);
208
209        impl<'tcx> Visitor<'tcx> for HasStorageDead {
210            fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) {
211                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
212                    self.0.insert(local);
213                }
214            }
215        }
216
217        if locals_are_invalidated_at_exit {
218            LocalsStateAtExit::AllAreInvalidated
219        } else {
220            let mut has_storage_dead =
221                HasStorageDead(DenseBitSet::new_empty(body.local_decls.len()));
222            has_storage_dead.visit_body(body);
223            let mut has_storage_dead_or_moved = has_storage_dead.0;
224            for move_out in &move_data.move_outs {
225                has_storage_dead_or_moved.insert(move_data.base_local(move_out.path));
226            }
227            LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved }
228        }
229    }
230}
231
232struct GatherBorrows<'a, 'tcx> {
233    tcx: TyCtxt<'tcx>,
234    body: &'a Body<'tcx>,
235    borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
236    location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
237    activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
238    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
239
240    /// When we encounter a 2-phase borrow statement, it will always
241    /// be assigning into a temporary TEMP:
242    ///
243    ///    TEMP = &foo
244    ///
245    /// We add TEMP into this map with `b`, where `b` is the index of
246    /// the borrow. When we find a later use of this activation, we
247    /// remove from the map (and add to the "tombstone" set below).
248    pending_activations: FxIndexMap<mir::Local, BorrowIndex>,
249
250    locals_state_at_exit: LocalsStateAtExit,
251}
252
253impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
254    fn insert_borrow(&mut self, location: Location, borrow: BorrowData<'tcx>) -> BorrowIndex {
255        let idx = self.borrows.push(borrow);
256        match self.location_map.entry(location) {
257            Entry::Occupied(entry) => {
258                ::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!(
259                    "Inserting a borrow {idx:?} at {location:?} attempted to override an existing list {entry:?}"
260                );
261            }
262            Entry::Vacant(entry) => {
263                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]);
264            }
265        }
266        idx
267    }
268}
269
270impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
271    fn visit_assign(
272        &mut self,
273        assigned_place: &mir::Place<'tcx>,
274        rvalue: &mir::Rvalue<'tcx>,
275        location: mir::Location,
276    ) {
277        if let &mir::Rvalue::Ref(region, kind, borrowed_place) = rvalue {
278            if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
279                {
    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:279",
                        "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(279u32),
                        ::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);
280                return;
281            }
282
283            let region = region.as_var();
284            let borrow = |activation_location| BorrowData {
285                kind,
286                region,
287                reserve_location: location,
288                activation_location,
289                borrowed_place,
290                assigned_place: *assigned_place,
291            };
292
293            let idx = if !kind.is_two_phase_borrow() {
294                {
    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:294",
                        "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(294u32),
                        ::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);
295                self.insert_borrow(location, borrow(TwoPhaseActivation::NotTwoPhase))
296            } else {
297                // When we encounter a 2-phase borrow statement, it will always
298                // be assigning into a temporary TEMP:
299                //
300                //    TEMP = &foo
301                //
302                // so extract `temp`.
303                let Some(temp) = assigned_place.as_local() else {
304                    ::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!(
305                        self.body.source_info(location).span,
306                        "expected 2-phase borrow to assign to a local, not `{:?}`",
307                        assigned_place,
308                    );
309                };
310
311                // Consider the borrow not activated to start. When we find an activation, we'll update
312                // this field.
313                let idx = self.insert_borrow(location, borrow(TwoPhaseActivation::NotActivated));
314
315                // Insert `temp` into the list of pending activations. From
316                // now on, we'll be on the lookout for a use of it. Note that
317                // we are guaranteed that this use will come after the
318                // assignment.
319                let prev = self.pending_activations.insert(temp, idx);
320                {
    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");
321
322                idx
323            };
324
325            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
326        } else if let &mir::Rvalue::Reborrow(target, mutability, borrowed_place) = rvalue {
327            let borrowed_place_ty = borrowed_place.ty(self.body, self.tcx).ty;
328            let &ty::Adt(reborrowed_adt, _reborrowed_args) = borrowed_place_ty.kind() else {
329                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
330            };
331            let &ty::Adt(target_adt, assigned_args) = target.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
332            let Some(ty::GenericArgKind::Lifetime(region)) = assigned_args.get(0).map(|r| r.kind())
333            else {
334                ::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!(
335                    "hir-typeck passed but {} does not have a lifetime argument",
336                    if mutability == Mutability::Mut { "Reborrow" } else { "CoerceShared" }
337                );
338            };
339            let region = region.as_var();
340            let kind = if mutability == Mutability::Mut {
341                // Reborrow
342                if target_adt.did() != reborrowed_adt.did() {
343                    ::rustc_middle::util::bug::bug_fmt(format_args!("hir-typeck passed but Reborrow involves mismatching types at {0:?}",
        location))bug!(
344                        "hir-typeck passed but Reborrow involves mismatching types at {location:?}"
345                    )
346                }
347
348                mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
349            } else {
350                // CoerceShared
351                if target_adt.did() == reborrowed_adt.did() {
352                    ::rustc_middle::util::bug::bug_fmt(format_args!("hir-typeck passed but CoerceShared involves matching types at {0:?}",
        location))bug!(
353                        "hir-typeck passed but CoerceShared involves matching types at {location:?}"
354                    )
355                }
356                mir::BorrowKind::Shared
357            };
358            let borrow = BorrowData {
359                kind,
360                region,
361                reserve_location: location,
362                activation_location: TwoPhaseActivation::NotTwoPhase,
363                borrowed_place,
364                assigned_place: *assigned_place,
365            };
366            let idx = self.insert_borrow(location, borrow);
367
368            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
369        }
370
371        self.super_assign(assigned_place, rvalue, location)
372    }
373
374    fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) {
375        if !context.is_use() {
376            return;
377        }
378
379        // We found a use of some temporary TMP
380        // check whether we (earlier) saw a 2-phase borrow like
381        //
382        //     TMP = &mut place
383        let Some(&borrow_index) = self.pending_activations.get(&temp) else {
384            return;
385        };
386        let borrow_data = &mut self.borrows[borrow_index];
387
388        // Watch out: the use of TMP in the borrow itself
389        // doesn't count as an activation. =)
390        if borrow_data.reserve_location == location
391            && context == PlaceContext::MutatingUse(MutatingUseContext::Store)
392        {
393            return;
394        }
395
396        if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location {
397            ::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!(
398                self.body.source_info(location).span,
399                "found two uses for 2-phase borrow temporary {:?}: \
400                {:?} and {:?}",
401                temp,
402                location,
403                other_location,
404            );
405        }
406
407        // Otherwise, this is the unique later use that we expect.
408        // Double check: This borrow is indeed a two-phase borrow (that is,
409        // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
410        // we've not found any other activations (checked above).
411        {
    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!(
412            borrow_data.activation_location,
413            TwoPhaseActivation::NotActivated,
414            "never found an activation for this borrow!",
415        );
416        self.activation_map.entry(location).or_default().push(borrow_index);
417
418        borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
419    }
420
421    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
422        if let &mir::Rvalue::Ref(region, kind, place) = rvalue {
423            // double-check that we already registered a BorrowData for this
424
425            let idxs = &self.location_map[&location];
426            for idx in idxs {
427                let borrow_data = &self.borrows[*idx];
428                {
    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);
429                {
    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);
430                {
    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());
431                {
    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);
432            }
433        }
434
435        self.super_rvalue(rvalue, location)
436    }
437}