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 borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
25
26 location_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
38
39 activation_map: FxHashMap<Location, SmallVec<[BorrowIndex; 1]>>,
41
42 local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
44
45 locals_state_at_exit: LocalsStateAtExit,
46}
47
48impl<'tcx> BorrowSet<'tcx> {
49 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 pub fn iter(&self) -> impl Iterator<Item = &BorrowData<'tcx>> {
87 self.borrows.iter()
88 }
89
90 pub fn locals_state_at_exit(&self) -> &LocalsStateAtExit {
92 &self.locals_state_at_exit
93 }
94
95 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 pub fn activations_at_location(&self, location: &Location) -> &[BorrowIndex] {
106 self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
107 }
108
109 pub fn borrows_at_location(&self, location: &Location) -> Option<&[BorrowIndex]> {
111 self.location_map.get(location).map(|v| v.as_slice())
112 }
113
114 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#[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 pub(crate) reserve_location: Location,
142 pub(crate) activation_location: TwoPhaseActivation,
144 pub(crate) kind: mir::BorrowKind,
146 pub(crate) region: RegionVid,
148 pub(crate) borrowed_place: mir::Place<'tcx>,
150 pub(crate) assigned_place: mir::Place<'tcx>,
152}
153
154impl<'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 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 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 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 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 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 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/feaadeeaca7db0594da854e7c8c07495341c7439/compiler/rustc_borrowck/src/borrow_set.rs:429",
"rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/feaadeeaca7db0594da854e7c8c07495341c7439/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/feaadeeaca7db0594da854e7c8c07495341c7439/compiler/rustc_borrowck/src/borrow_set.rs:444",
"rustc_borrowck::borrow_set", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/feaadeeaca7db0594da854e7c8c07495341c7439/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 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 let idx = self.insert_borrow(location, borrow(TwoPhaseActivation::NotActivated));
464
465 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 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 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 let Some(&borrow_index) = self.pending_activations.get(&temp) else {
534 return;
535 };
536 let borrow_data = &mut self.borrows[borrow_index];
537
538 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 {
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 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, ®ion.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}