|
1 | 1 | 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}; |
3 | 3 | use crate::build::Builder;
|
| 4 | +use rustc_data_structures::fx::FxIndexSet; |
4 | 5 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
5 | 6 | use rustc_middle::mir::*;
|
6 | 7 | use rustc_middle::thir::{self, *};
|
@@ -260,3 +261,82 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
260 | 261 | MatchPair { place, test_case, subpairs, pattern }
|
261 | 262 | }
|
262 | 263 | }
|
| 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