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, PlaceElem, traversal};
11use rustc_middle::ty;
12use rustc_middle::ty::data_structures::IndexSet;
13use rustc_middle::ty::{RegionVid, TyCtxt};
14use rustc_mir_dataflow::move_paths::MoveData;
15use rustc_span::{bug, span_bug};
16use smallvec::{SmallVec, smallvec};
17use tracing::debug;
18
19use crate::BorrowIndex;
20use crate::place_ext::PlaceExt;
21
22pub struct BorrowSet<'tcx> {
23    /// BorrowData storage.
24    borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
25
26    /// The fundamental map relating bitvector indexes to the borrows
27    /// in the MIR. Each borrow of a reference is uniquely identified in the MIR
28    /// by the `Location` of the assignment statement in which it
29    /// appears on the right hand side, but for generic Reborrow there may be
30    /// multiple borrows per location. Thus the location is the map
31    /// key, and it identifies one or more `BorrowIndex` values.
32    ///
33    /// FIXME(reborrow): if the Reborrow experiment is rejected, this can be turned
34    /// back into a FxIndexMap<Location, BorrowData<'tcx> or BorrowIndex>. See [PR].
35    ///
36    /// [PR]: github.com/rust-lang/rust/pull/159449
37    location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
38
39    /// Locations which activate borrows.
40    activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
41
42    /// Map from local to all the borrows on that local.
43    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
44
45    locals_state_at_exit: LocalsStateAtExit,
46}
47
48impl<'tcx> BorrowSet<'tcx> {
49    // Public method to support Aquascope.
50    pub fn build(
51        tcx: TyCtxt<'tcx>,
52        body: &Body<'tcx>,
53        locals_are_invalidated_at_exit: bool,
54        move_data: &MoveData<'tcx>,
55    ) -> Self {
56        let mut visitor = GatherBorrows {
57            tcx,
58            body,
59            borrows: Default::default(),
60            location_map: Default::default(),
61            activation_map: Default::default(),
62            local_map: Default::default(),
63            pending_activations: Default::default(),
64            locals_state_at_exit: LocalsStateAtExit::build(
65                locals_are_invalidated_at_exit,
66                body,
67                move_data,
68            ),
69        };
70
71        for (block, block_data) in traversal::preorder(body) {
72            visitor.visit_basic_block_data(block, block_data);
73        }
74
75        BorrowSet {
76            borrows: visitor.borrows,
77            location_map: visitor.location_map,
78            activation_map: visitor.activation_map,
79            local_map: visitor.local_map,
80            locals_state_at_exit: visitor.locals_state_at_exit,
81        }
82    }
83
84    // Public method to support Aquascope and Creusot.
85    /// Iterate through all BorrowData in the BorrowSet.
86    pub fn iter(&self) -> impl Iterator<Item = &BorrowData<'tcx>> {
87        self.borrows.iter()
88    }
89
90    // Public method to support Creusot.
91    pub fn locals_state_at_exit(&self) -> &LocalsStateAtExit {
92        &self.locals_state_at_exit
93    }
94
95    // Public method to support Creusot.
96    pub fn len(&self) -> usize {
97        self.borrows.len()
98    }
99
100    pub fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
101        self.borrows.iter_enumerated()
102    }
103
104    // Public method to support Creusot.
105    pub fn activations_at_location(&self, location: &Location) -> &[BorrowIndex] {
106        self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
107    }
108
109    // Public method to support Creusot.
110    pub fn borrows_at_location(&self, location: &Location) -> Option<&[BorrowIndex]> {
111        self.location_map.get(location).map(|v| v.as_slice())
112    }
113
114    // Public method to support Creusot.
115    pub fn borrows_on_local(&self, local: Local) -> Option<&IndexSet<BorrowIndex>> {
116        self.local_map.get(&local)
117    }
118}
119
120impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
121    type Output = BorrowData<'tcx>;
122
123    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
124        &self.borrows[index]
125    }
126}
127
128/// Location where a two-phase borrow is activated, if a borrow
129/// is in fact a two-phase borrow.
130#[derive(#[automatically_derived]
impl ::core::marker::Copy for TwoPhaseActivation { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for TwoPhaseActivation { }
#[automatically_derived]
impl ::core::clone::Clone for TwoPhaseActivation {
    #[inline]
    fn clone(&self) -> TwoPhaseActivation {
        let _: ::core::clone::AssertParamIsClone<Location>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for TwoPhaseActivation { }
#[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)]
131pub enum TwoPhaseActivation {
132    NotTwoPhase,
133    NotActivated,
134    ActivatedAt(Location),
135}
136
137#[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)]
138pub struct BorrowData<'tcx> {
139    /// Location where the borrow reservation starts.
140    /// In many cases, this will be equal to the activation location but not always.
141    pub(crate) reserve_location: Location,
142    /// Location where the borrow is activated.
143    pub(crate) activation_location: TwoPhaseActivation,
144    /// What kind of borrow this is
145    pub(crate) kind: mir::BorrowKind,
146    /// The region for which this borrow is live
147    pub(crate) region: RegionVid,
148    /// Place from which we are borrowing
149    pub(crate) borrowed_place: mir::Place<'tcx>,
150    /// Place to which the borrow was stored
151    pub(crate) assigned_place: mir::Place<'tcx>,
152}
153
154// These methods are public to support borrowck consumers.
155impl<'tcx> BorrowData<'tcx> {
156    pub fn reserve_location(&self) -> Location {
157        self.reserve_location
158    }
159
160    pub fn activation_location(&self) -> TwoPhaseActivation {
161        self.activation_location
162    }
163
164    pub fn kind(&self) -> mir::BorrowKind {
165        self.kind
166    }
167
168    pub fn region(&self) -> RegionVid {
169        self.region
170    }
171
172    pub fn borrowed_place(&self) -> mir::Place<'tcx> {
173        self.borrowed_place
174    }
175
176    pub fn assigned_place(&self) -> mir::Place<'tcx> {
177        self.assigned_place
178    }
179}
180
181impl<'tcx> fmt::Display for BorrowData<'tcx> {
182    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
183        let kind = match self.kind {
184            mir::BorrowKind::Shared => "",
185            mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
186            mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
187            mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
188            // FIXME: differentiate `TwoPhaseBorrow`
189            mir::BorrowKind::Mut {
190                kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow,
191            } => "mut ",
192        };
193        w.write_fmt(format_args!("&{0:?} {1}{2:?}", self.region, kind,
        self.borrowed_place))write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
194    }
195}
196
197pub enum LocalsStateAtExit {
198    AllAreInvalidated,
199    SomeAreInvalidated { has_storage_dead_or_moved: DenseBitSet<Local> },
200}
201
202impl LocalsStateAtExit {
203    fn build<'tcx>(
204        locals_are_invalidated_at_exit: bool,
205        body: &Body<'tcx>,
206        move_data: &MoveData<'tcx>,
207    ) -> Self {
208        struct HasStorageDead(DenseBitSet<Local>);
209
210        impl<'tcx> Visitor<'tcx> for HasStorageDead {
211            fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) {
212                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
213                    self.0.insert(local);
214                }
215            }
216        }
217
218        if locals_are_invalidated_at_exit {
219            LocalsStateAtExit::AllAreInvalidated
220        } else {
221            let mut has_storage_dead =
222                HasStorageDead(DenseBitSet::new_empty(body.local_decls.len()));
223            has_storage_dead.visit_body(body);
224            let mut has_storage_dead_or_moved = has_storage_dead.0;
225            for move_out in &move_data.move_outs {
226                has_storage_dead_or_moved.insert(move_data.base_local(move_out.path));
227            }
228            LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved }
229        }
230    }
231}
232
233struct GatherBorrows<'a, 'tcx> {
234    tcx: TyCtxt<'tcx>,
235    body: &'a Body<'tcx>,
236    borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
237    location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
238    activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
239    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
240
241    /// When we encounter a 2-phase borrow statement, it will always
242    /// be assigning into a temporary TEMP:
243    ///
244    ///    TEMP = &foo
245    ///
246    /// We add TEMP into this map with `b`, where `b` is the index of
247    /// the borrow. When we find a later use of this activation, we
248    /// remove from the map (and add to the "tombstone" set below).
249    pending_activations: FxIndexMap<mir::Local, BorrowIndex>,
250
251    locals_state_at_exit: LocalsStateAtExit,
252}
253
254impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
255    fn insert_borrow(&mut self, location: Location, borrow: BorrowData<'tcx>) -> BorrowIndex {
256        let idx = self.borrows.push(borrow);
257        match self.location_map.entry(location) {
258            Entry::Occupied(entry) => {
259                bug_impl(None,
    format_args!("Inserting a borrow {0:?} at {1:?} attempted to override an existing list {2:?}",
        idx, location, entry), Location::caller());bug!(
260                    "Inserting a borrow {idx:?} at {location:?} attempted to override an existing list {entry:?}"
261                );
262            }
263            Entry::Vacant(entry) => {
264                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]);
265            }
266        }
267        idx
268    }
269
270    fn insert_borrows(
271        &mut self,
272        location: Location,
273        borrows: SmallVec<[BorrowData<'tcx>; 1]>,
274    ) -> SmallVec<[BorrowIndex; 1]> {
275        let mut idxs = SmallVec::<[BorrowIndex; 1]>::with_capacity(borrows.len());
276        // FIXME(reborrow): why doesn't SmallVec offer reserve?
277        for borrow in borrows {
278            idxs.push(self.borrows.push(borrow));
279        }
280        match self.location_map.entry(location) {
281            Entry::Occupied(entry) => {
282                bug_impl(None,
    format_args!("Inserting borrows {0:?} at {1:?} attempted to override an existing list {2:?}",
        idxs, location, entry), Location::caller());bug!(
283                    "Inserting borrows {idxs:?} at {location:?} attempted to override an existing list {entry:?}"
284                );
285            }
286            Entry::Vacant(entry) => {
287                entry.insert(idxs.clone());
288            }
289        }
290        idxs
291    }
292
293    fn gather_reborrows(
294        &mut self,
295        v: &mut SmallVec<[BorrowData<'tcx>; 1]>,
296        kind: mir::BorrowKind,
297        location: Location,
298        target_adt: ty::AdtDef<'tcx>,
299        target_args: &'tcx ty::List<ty::GenericArg<'tcx>>,
300        target_place: mir::Place<'tcx>,
301        source_adt: ty::AdtDef<'tcx>,
302        source_args: &'tcx ty::List<ty::GenericArg<'tcx>>,
303        source_place: mir::Place<'tcx>,
304    ) {
305        let mut did_reborrow = false;
306        for (source_idx, source_field) in source_adt.all_fields().enumerate() {
307            let source_field_ty = source_field.ty(self.tcx, source_args).skip_norm_wip();
308            match source_field_ty.kind() {
309                ty::Ref(source_region, _, source_mutability) if source_mutability.is_mut() => {
310                    if source_region.is_static() {
311                        bug_impl(None,
    format_args!("Cannot implement Reborrow on a type containing a &\'static mut T field"),
    Location::caller());bug!(
312                            "Cannot implement Reborrow on a type containing a &'static mut T field"
313                        );
314                    }
315                    let Some((target_idx, target_field)) = target_adt
316                        .all_fields()
317                        .enumerate()
318                        .find(|(_, f)| f.name == source_field.name)
319                    else {
320                        // Reborrow dropped this field.
321                        continue;
322                    };
323                    let ty::Ref(target_region, _, _) =
324                        target_field.ty(self.tcx, target_args).skip_norm_wip().kind()
325                    else {
326                        bug_impl(None,
    format_args!("Reborrow source field type is &mut T but target field is not a reference"),
    Location::caller());bug!(
327                            "Reborrow source field type is &mut T but target field is not a reference"
328                        );
329                    };
330
331                    did_reborrow = true;
332                    let source_field_deref_place = source_place.project_deeper(
333                        &[PlaceElem::Field(source_idx.into(), source_field_ty), PlaceElem::Deref],
334                        self.tcx,
335                    );
336                    let target_field_place = target_place.project_to_field(
337                        target_idx.into(),
338                        &self.body.local_decls,
339                        self.tcx,
340                    );
341                    v.push(BorrowData {
342                        kind,
343                        region: target_region.as_var(),
344                        reserve_location: location,
345                        activation_location: TwoPhaseActivation::NotTwoPhase,
346                        borrowed_place: source_field_deref_place,
347                        assigned_place: target_field_place,
348                    });
349                }
350                ty::Adt(source_field_adt, source_field_args)
351                    if source_field_args.get(0).is_some_and(|f| f.as_region().is_some())
352                        && !self.tcx.type_is_copy_modulo_regions(
353                            self.body.typing_env(self.tcx),
354                            self.tcx.erase_and_anonymize_regions(source_field_ty),
355                        ) =>
356                {
357                    let Some((target_idx, target_field)) = target_adt
358                        .all_fields()
359                        .enumerate()
360                        .find(|(_, f)| f.name == source_field.name)
361                    else {
362                        // Reborrow dropped this field.
363                        continue;
364                    };
365                    let ty::Adt(target_field_adt, target_field_args) =
366                        target_field.ty(self.tcx, target_args).skip_norm_wip().kind()
367                    else {
368                        bug_impl(None,
    format_args!("Reborrow source field type is a !Copy ADT but target field is not"),
    Location::caller());bug!("Reborrow source field type is a !Copy ADT but target field is not");
369                    };
370
371                    did_reborrow = true;
372                    let source_field_place = source_place.project_to_field(
373                        source_idx.into(),
374                        &self.body.local_decls,
375                        self.tcx,
376                    );
377                    let target_field_place = target_place.project_to_field(
378                        target_idx.into(),
379                        &self.body.local_decls,
380                        self.tcx,
381                    );
382                    self.gather_reborrows(
383                        v,
384                        kind,
385                        location,
386                        *target_field_adt,
387                        target_field_args,
388                        target_field_place,
389                        *source_field_adt,
390                        source_field_args,
391                        source_field_place,
392                    );
393                }
394                _ => continue,
395            }
396        }
397        if !did_reborrow {
398            // Key point: if source contained no reference, a phantom dereference must be performed
399            // to avoid capturing the local variable's place.
400            let source_phantom_deref_place =
401                source_place.project_deeper(&[PlaceElem::PhantomDeref], self.tcx);
402            if target_args.regions().count() != 1 {
403                bug_impl(None,
    format_args!("ADT containing no \'&mut T\' or \'T: Reborrow\' fields must only have one lifetime to implement Reborrow"),
    Location::caller());bug!(
404                    "ADT containing no '&mut T' or 'T: Reborrow' fields must only have one lifetime to implement Reborrow"
405                );
406            }
407            let target_region = target_args.regions().next().unwrap();
408            v.push(BorrowData {
409                kind,
410                region: target_region.as_var(),
411                reserve_location: location,
412                activation_location: TwoPhaseActivation::NotTwoPhase,
413                borrowed_place: source_phantom_deref_place,
414                assigned_place: target_place,
415            });
416        }
417    }
418}
419
420impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
421    fn visit_assign(
422        &mut self,
423        assigned_place: &mir::Place<'tcx>,
424        rvalue: &mir::Rvalue<'tcx>,
425        location: mir::Location,
426    ) {
427        if let &mir::Rvalue::Ref(region, kind, borrowed_place) = rvalue {
428            if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
429                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_borrowck/src/borrow_set.rs:429",
                        "rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_borrowck/src/borrow_set.rs"),
                        ::tracing_core::__macro_support::Option::Some(429u32),
                        ::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);
430                return;
431            }
432
433            let region = region.as_var();
434            let borrow = |activation_location| BorrowData {
435                kind,
436                region,
437                reserve_location: location,
438                activation_location,
439                borrowed_place,
440                assigned_place: *assigned_place,
441            };
442
443            let idx = if !kind.is_two_phase_borrow() {
444                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_borrowck/src/borrow_set.rs:444",
                        "rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_borrowck/src/borrow_set.rs"),
                        ::tracing_core::__macro_support::Option::Some(444u32),
                        ::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);
445                self.insert_borrow(location, borrow(TwoPhaseActivation::NotTwoPhase))
446            } else {
447                // When we encounter a 2-phase borrow statement, it will always
448                // be assigning into a temporary TEMP:
449                //
450                //    TEMP = &foo
451                //
452                // so extract `temp`.
453                let Some(temp) = assigned_place.as_local() else {
454                    bug_impl(Some(self.body.source_info(location).span),
    format_args!("expected 2-phase borrow to assign to a local, not `{0:?}`",
        assigned_place), Location::caller());span_bug!(
455                        self.body.source_info(location).span,
456                        "expected 2-phase borrow to assign to a local, not `{:?}`",
457                        assigned_place,
458                    );
459                };
460
461                // Consider the borrow not activated to start. When we find an activation, we'll update
462                // this field.
463                let idx = self.insert_borrow(location, borrow(TwoPhaseActivation::NotActivated));
464
465                // Insert `temp` into the list of pending activations. From
466                // now on, we'll be on the lookout for a use of it. Note that
467                // we are guaranteed that this use will come after the
468                // assignment.
469                let prev = self.pending_activations.insert(temp, idx);
470                {
    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");
471
472                idx
473            };
474
475            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
476        } else if let &mir::Rvalue::Reborrow(target, mutability, source_place) = rvalue {
477            let source_ty = source_place.ty(self.body, self.tcx).ty;
478            let &ty::Adt(source_adt, source_args) = source_ty.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
479            let &ty::Adt(target_adt, target_args) = target.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
480
481            let kind = if mutability == Mutability::Mut {
482                // Reborrow
483                if target_adt.did() != source_adt.did() {
484                    bug_impl(None,
    format_args!("hir-typeck passed but Reborrow involves mismatching types at {0:?}",
        location), Location::caller())bug!(
485                        "hir-typeck passed but Reborrow involves mismatching types at {location:?}"
486                    )
487                }
488
489                mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
490            } else {
491                // CoerceShared
492                if target_adt.did() == source_adt.did() {
493                    bug_impl(None,
    format_args!("hir-typeck passed but CoerceShared involves matching types at {0:?}",
        location), Location::caller())bug!(
494                        "hir-typeck passed but CoerceShared involves matching types at {location:?}"
495                    )
496                }
497                mir::BorrowKind::Shared
498            };
499
500            let mut reborrows = ::smallvec::SmallVec::new()smallvec![];
501            self.gather_reborrows(
502                &mut reborrows,
503                kind,
504                location,
505                target_adt,
506                target_args,
507                *assigned_place,
508                source_adt,
509                source_args,
510                source_place,
511            );
512
513            let idxs = self.insert_borrows(location, reborrows);
514
515            let locals = self.local_map.entry(source_place.local).or_default();
516            for idx in idxs {
517                locals.insert(idx);
518            }
519        }
520
521        self.super_assign(assigned_place, rvalue, location)
522    }
523
524    fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) {
525        if !context.is_use() {
526            return;
527        }
528
529        // We found a use of some temporary TMP
530        // check whether we (earlier) saw a 2-phase borrow like
531        //
532        //     TMP = &mut place
533        let Some(&borrow_index) = self.pending_activations.get(&temp) else {
534            return;
535        };
536        let borrow_data = &mut self.borrows[borrow_index];
537
538        // Watch out: the use of TMP in the borrow itself
539        // doesn't count as an activation. =)
540        if borrow_data.reserve_location == location
541            && context == PlaceContext::MutatingUse(MutatingUseContext::Store)
542        {
543            return;
544        }
545
546        if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location {
547            bug_impl(Some(self.body.source_info(location).span),
    format_args!("found two uses for 2-phase borrow temporary {0:?}: {1:?} and {2:?}",
        temp, location, other_location), Location::caller());span_bug!(
548                self.body.source_info(location).span,
549                "found two uses for 2-phase borrow temporary {:?}: \
550                {:?} and {:?}",
551                temp,
552                location,
553                other_location,
554            );
555        }
556
557        // Otherwise, this is the unique later use that we expect.
558        // Double check: This borrow is indeed a two-phase borrow (that is,
559        // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
560        // we've not found any other activations (checked above).
561        {
    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!(
562            borrow_data.activation_location,
563            TwoPhaseActivation::NotActivated,
564            "never found an activation for this borrow!",
565        );
566        self.activation_map.entry(location).or_default().push(borrow_index);
567
568        borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
569    }
570
571    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
572        if let &mir::Rvalue::Ref(region, kind, place) = rvalue {
573            // double-check that we already registered a BorrowData for this
574
575            let idxs = &self.location_map[&location];
576            for idx in idxs {
577                let borrow_data = &self.borrows[*idx];
578                {
    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);
579                {
    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);
580                {
    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());
581                {
    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);
582            }
583        }
584
585        self.super_rvalue(rvalue, location)
586    }
587}