Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ca5edfa

Browse files
committed
Collect fake borrows ahead of time
1 parent 2966611 commit ca5edfa

File tree

2 files changed

+83
-40
lines changed

2 files changed

+83
-40
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315315
// The set of places that we are creating fake borrows of. If there are
316316
// no match guards then we don't need any fake borrows, so don't track
317317
// them.
318-
let mut fake_borrows = match_has_guard.then(FxIndexSet::default);
318+
let mut fake_borrows = match_has_guard
319+
.then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates));
319320

320321
let otherwise_block = self.cfg.start_new_block();
321322

@@ -1373,37 +1374,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13731374
assert!(candidate.pre_binding_block.is_none());
13741375
assert!(candidate.subcandidates.is_empty());
13751376

1376-
if let Some(fake_borrows) = fake_borrows {
1377-
// Insert a borrows of prefixes of places that are bound and are
1378-
// behind a dereference projection.
1379-
//
1380-
// These borrows are taken to avoid situations like the following:
1381-
//
1382-
// match x[10] {
1383-
// _ if { x = &[0]; false } => (),
1384-
// y => (), // Out of bounds array access!
1385-
// }
1386-
//
1387-
// match *x {
1388-
// // y is bound by reference in the guard and then by copy in the
1389-
// // arm, so y is 2 in the arm!
1390-
// y if { y == 1 && (x = &2) == () } => y,
1391-
// _ => 3,
1392-
// }
1393-
for Binding { source, .. } in &candidate.bindings {
1394-
if let Some(i) =
1395-
source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref)
1396-
{
1397-
let proj_base = &source.projection[..i];
1398-
1399-
fake_borrows.insert(Place {
1400-
local: source.local,
1401-
projection: self.tcx.mk_place_elems(proj_base),
1402-
});
1403-
}
1404-
}
1405-
}
1406-
14071377
candidate.pre_binding_block = Some(start_block);
14081378
let otherwise_block = self.cfg.start_new_block();
14091379
if candidate.has_guard {
@@ -1656,13 +1626,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16561626
_ => {}
16571627
}
16581628

1659-
// Insert a Shallow borrow of any places that is switched on.
1660-
if let Some(fb) = fake_borrows
1661-
&& let Some(resolved_place) = match_place.try_to_place(self)
1662-
{
1663-
fb.insert(resolved_place);
1664-
}
1665-
16661629
(match_place, test)
16671630
}
16681631

compiler/rustc_mir_build/src/build/matches/util.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
2-
use crate::build::matches::{FlatPat, MatchPair, TestCase};
2+
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
33
use crate::build::Builder;
4+
use rustc_data_structures::fx::FxIndexSet;
45
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
56
use rustc_middle::mir::*;
67
use rustc_middle::thir::{self, *};
@@ -260,3 +261,82 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
260261
MatchPair { place, test_case, subpairs, pattern }
261262
}
262263
}
264+
265+
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
266+
cx: &'a mut Builder<'b, 'tcx>,
267+
fake_borrows: FxIndexSet<Place<'tcx>>,
268+
}
269+
270+
impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
271+
pub(super) fn collect_fake_borrows(
272+
cx: &'a mut Builder<'b, 'tcx>,
273+
candidates: &[&mut Candidate<'_, 'tcx>],
274+
) -> FxIndexSet<Place<'tcx>> {
275+
let mut collector = Self { cx, fake_borrows: FxIndexSet::default() };
276+
for candidate in candidates.iter() {
277+
collector.visit_candidate(candidate);
278+
}
279+
collector.fake_borrows
280+
}
281+
282+
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
283+
for binding in &candidate.bindings {
284+
self.visit_binding(binding);
285+
}
286+
for match_pair in &candidate.match_pairs {
287+
self.visit_match_pair(match_pair);
288+
}
289+
}
290+
291+
fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) {
292+
for binding in &flat_pat.bindings {
293+
self.visit_binding(binding);
294+
}
295+
for match_pair in &flat_pat.match_pairs {
296+
self.visit_match_pair(match_pair);
297+
}
298+
}
299+
300+
fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) {
301+
if let TestCase::Or { pats, .. } = &match_pair.test_case {
302+
for flat_pat in pats.iter() {
303+
self.visit_flat_pat(flat_pat)
304+
}
305+
} else {
306+
// Insert a Shallow borrow of any place that is switched on.
307+
if let Some(resolved_place) = match_pair.place.try_to_place(self.cx) {
308+
self.fake_borrows.insert(resolved_place);
309+
}
310+
311+
for subpair in &match_pair.subpairs {
312+
self.visit_match_pair(subpair);
313+
}
314+
}
315+
}
316+
317+
fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) {
318+
// Insert a borrows of prefixes of places that are bound and are
319+
// behind a dereference projection.
320+
//
321+
// These borrows are taken to avoid situations like the following:
322+
//
323+
// match x[10] {
324+
// _ if { x = &[0]; false } => (),
325+
// y => (), // Out of bounds array access!
326+
// }
327+
//
328+
// match *x {
329+
// // y is bound by reference in the guard and then by copy in the
330+
// // arm, so y is 2 in the arm!
331+
// y if { y == 1 && (x = &2) == () } => y,
332+
// _ => 3,
333+
// }
334+
if let Some(i) = source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) {
335+
let proj_base = &source.projection[..i];
336+
self.fake_borrows.insert(Place {
337+
local: source.local,
338+
projection: self.cx.tcx.mk_place_elems(proj_base),
339+
});
340+
}
341+
}
342+
}

0 commit comments

Comments
 (0)