Skip to content

Commit 81560a4

Browse files
committed
Re-establish deref temporaries after fake edges
1 parent 557c8c4 commit 81560a4

File tree

4 files changed

+80
-21
lines changed

4 files changed

+80
-21
lines changed

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
927927
}
928928
}
929929

930+
/// A temporary that must be set like `let temp = Deref::deref(&place)` after the candidate
931+
/// `pre_binding_block`. This is because fake edges prevent us from keeping the temporaries we set
932+
/// up while testing which branch to take.
933+
#[derive(Debug, Copy, Clone)]
934+
struct DerefTemporary<'tcx> {
935+
place: Place<'tcx>,
936+
temp: Place<'tcx>,
937+
ty: Ty<'tcx>,
938+
span: Span,
939+
}
940+
930941
/// Data extracted from a pattern that doesn't affect which branch is taken. Collected during
931942
/// pattern simplification and not mutated later.
932943
#[derive(Debug, Clone, Default)]
@@ -939,11 +950,15 @@ struct PatternExtraData<'tcx> {
939950

940951
/// Types that must be asserted.
941952
ascriptions: Vec<Ascription<'tcx>>,
953+
954+
/// Temporaries that must be set up in order.
955+
deref_temps: Vec<DerefTemporary<'tcx>>,
942956
}
943957

944958
impl<'tcx> PatternExtraData<'tcx> {
945959
fn is_empty(&self) -> bool {
946-
self.bindings.is_empty() && self.ascriptions.is_empty()
960+
// FIXME(deref_patterns): can we merge trivial subcandidates that use deref patterns?
961+
self.bindings.is_empty() && self.ascriptions.is_empty() && self.deref_temps.is_empty()
947962
}
948963
}
949964

@@ -970,6 +985,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
970985
span: pattern.span,
971986
bindings: Vec::new(),
972987
ascriptions: Vec::new(),
988+
deref_temps: Vec::new(),
973989
},
974990
};
975991
cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data);
@@ -1986,6 +2002,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19862002
block = fresh_block;
19872003
}
19882004

2005+
for d in collected_data.iter() {
2006+
for deref_call in d.deref_temps.iter() {
2007+
// Re-establish `Deref::deref` temporaries because false edges trick borrowck into
2008+
// believing they may not be initialized.
2009+
let next_block = self.cfg.start_new_block();
2010+
self.call_deref(
2011+
block,
2012+
next_block,
2013+
deref_call.place,
2014+
deref_call.ty,
2015+
deref_call.temp,
2016+
deref_call.span,
2017+
);
2018+
block = next_block;
2019+
}
2020+
}
2021+
19892022
self.ascribe_types(block, collected_data.iter().flat_map(|d| &d.ascriptions).cloned());
19902023

19912024
// rust-lang/rust#27282: The `autoref` business deserves some

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
//! sort of test: for example, testing which variant an enum is, or
1313
//! testing a value against a constant.
1414
15-
use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase};
15+
use crate::build::matches::{
16+
Candidate, DerefTemporary, FlatPat, MatchPair, PatternExtraData, TestCase,
17+
};
1618
use crate::build::Builder;
1719

1820
use std::mem;
@@ -44,6 +46,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4446
// after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
4547
// match lowering forces us to lower bindings inside or-patterns last.
4648
for mut match_pair in mem::take(match_pairs) {
49+
if let TestCase::Deref { temp } = &match_pair.test_case {
50+
// Re-establish these temporaries after matching the candidate in case we have
51+
// bindings that depend on them.
52+
extra_data.deref_temps.push(DerefTemporary {
53+
place: match_pair.place.to_place(self),
54+
temp: *temp,
55+
ty: match_pair.pattern.ty,
56+
span: match_pair.pattern.span,
57+
});
58+
}
59+
4760
self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
4861
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
4962
if let Some(binding) = binding {
Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
1+
//@ run-pass
12
#![feature(deref_patterns)]
23
#![allow(incomplete_features)]
34

4-
fn main() {
5-
// FIXME(deref_patterns): fix bindings wrt fake edges
6-
match vec![1] {
7-
box [] => unreachable!(),
8-
box [x] => assert_eq!(x, 1),
9-
//~^ ERROR used binding isn't initialized
10-
_ => unreachable!(),
5+
fn simple_vec(vec: Vec<u32>) -> u32 {
6+
match vec {
7+
box [] => 100,
8+
// FIXME(deref_patterns): fake borrows break guards
9+
// box [x] if x == 4 => x + 4,
10+
box [x] => x,
11+
box [1, x] => x + 200,
12+
box ref slice => slice.iter().sum(),
13+
_ => 2000,
14+
}
15+
}
16+
17+
fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
18+
match vecvec {
19+
box [] => 0,
20+
box [box [x]] => x,
21+
box [box [0, x] | box [1, x]] => x,
22+
box [ref x] => x.iter().sum(),
23+
box [box [], box [1, x, y]] => y - x,
24+
_ => 2000,
1125
}
1226
}
27+
28+
fn main() {
29+
assert_eq!(simple_vec(vec![1]), 1);
30+
assert_eq!(simple_vec(vec![1, 2]), 202);
31+
assert_eq!(simple_vec(vec![1, 2, 3]), 6);
32+
33+
assert_eq!(nested_vec(vec![vec![0, 42]]), 42);
34+
assert_eq!(nested_vec(vec![vec![1, 42]]), 42);
35+
assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6);
36+
assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1);
37+
}

tests/ui/pattern/deref-patterns/bindings.stderr

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)