Skip to content

Commit 0197f98

Browse files
committed
change how we declare bindings so that unreachable arms don't
cause panics
1 parent 96a3cd0 commit 0197f98

File tree

2 files changed

+39
-42
lines changed

2 files changed

+39
-42
lines changed

src/librustc_mir/build/matches/mod.rs

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ impl<H:Hair> Builder<H> {
3434
let discriminant_lvalue =
3535
unpack!(block = self.as_lvalue(block, discriminant));
3636

37+
// Before we do anything, create uninitialized variables with
38+
// suitable extent for all of the bindings in this match. It's
39+
// easiest to do this up front because some of these arms may
40+
// be unreachable or reachable multiple times.
41+
let var_extent = self.extent_of_innermost_scope().unwrap();
42+
for arm in &arms {
43+
self.declare_bindings(var_extent, arm.patterns[0].clone());
44+
}
45+
3746
let mut arm_blocks = ArmBlocks {
3847
blocks: arms.iter()
3948
.map(|_| self.cfg.start_new_block())
@@ -52,14 +61,13 @@ impl<H:Hair> Builder<H> {
5261
// reverse of the order in which candidates are written in the
5362
// source.
5463
let candidates: Vec<Candidate<H>> =
55-
arms.into_iter()
64+
arms.iter()
5665
.enumerate()
5766
.rev() // highest priority comes last
5867
.flat_map(|(arm_index, arm)| {
59-
let guard = arm.guard;
60-
arm.patterns.into_iter()
68+
arm.patterns.iter()
6169
.rev()
62-
.map(move |pat| (arm_index, pat, guard.clone()))
70+
.map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
6371
})
6472
.map(|(arm_index, pattern, guard)| {
6573
Candidate {
@@ -73,8 +81,7 @@ impl<H:Hair> Builder<H> {
7381

7482
// this will generate code to test discriminant_lvalue and
7583
// branch to the appropriate arm block
76-
let var_extent = self.extent_of_innermost_scope().unwrap();
77-
self.match_candidates(span, var_extent, &mut arm_blocks, candidates, block);
84+
self.match_candidates(span, &mut arm_blocks, candidates, block);
7885

7986
// all the arm blocks will rejoin here
8087
let end_block = self.cfg.start_new_block();
@@ -123,9 +130,12 @@ impl<H:Hair> Builder<H> {
123130
initializer: &Lvalue<H>)
124131
-> BlockAnd<()>
125132
{
133+
// first, creating the bindings
134+
self.declare_bindings(var_extent, irrefutable_pat.clone());
135+
126136
// create a dummy candidate
127137
let mut candidate = Candidate::<H> {
128-
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)],
138+
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
129139
bindings: vec![],
130140
guard: None,
131141
arm_index: 0, // since we don't call `match_candidates`, this field is unused
@@ -143,38 +153,38 @@ impl<H:Hair> Builder<H> {
143153
}
144154

145155
// now apply the bindings, which will also declare the variables
146-
self.bind_matched_candidate(block, var_extent, candidate.bindings);
156+
self.bind_matched_candidate(block, candidate.bindings);
147157

148158
block.unit()
149159
}
150160

151-
pub fn declare_uninitialized_variables(&mut self,
152-
var_extent: H::CodeExtent,
153-
pattern: PatternRef<H>)
161+
pub fn declare_bindings(&mut self,
162+
var_extent: H::CodeExtent,
163+
pattern: PatternRef<H>)
154164
{
155165
let pattern = self.hir.mirror(pattern);
156166
match pattern.kind {
157167
PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
158168
self.declare_binding(var_extent, mutability, name, var, ty, pattern.span);
159169
if let Some(subpattern) = subpattern {
160-
self.declare_uninitialized_variables(var_extent, subpattern);
170+
self.declare_bindings(var_extent, subpattern);
161171
}
162172
}
163173
PatternKind::Array { prefix, slice, suffix } |
164174
PatternKind::Slice { prefix, slice, suffix } => {
165175
for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
166-
self.declare_uninitialized_variables(var_extent, subpattern);
176+
self.declare_bindings(var_extent, subpattern);
167177
}
168178
}
169179
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
170180
}
171181
PatternKind::Deref { subpattern } => {
172-
self.declare_uninitialized_variables(var_extent, subpattern);
182+
self.declare_bindings(var_extent, subpattern);
173183
}
174184
PatternKind::Leaf { subpatterns } |
175185
PatternKind::Variant { subpatterns, .. } => {
176186
for subpattern in subpatterns {
177-
self.declare_uninitialized_variables(var_extent, subpattern.pattern);
187+
self.declare_bindings(var_extent, subpattern.pattern);
178188
}
179189
}
180190
}
@@ -249,13 +259,12 @@ struct Test<H:Hair> {
249259
impl<H:Hair> Builder<H> {
250260
fn match_candidates(&mut self,
251261
span: H::Span,
252-
var_extent: H::CodeExtent,
253262
arm_blocks: &mut ArmBlocks,
254263
mut candidates: Vec<Candidate<H>>,
255264
mut block: BasicBlock)
256265
{
257-
debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})",
258-
span, var_extent, block, candidates);
266+
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
267+
span, block, candidates);
259268

260269
// Start by simplifying candidates. Once this process is
261270
// complete, all the match pairs which remain require some
@@ -275,8 +284,7 @@ impl<H:Hair> Builder<H> {
275284
// If so, apply any bindings, test the guard (if any), and
276285
// branch to the arm.
277286
let candidate = candidates.pop().unwrap();
278-
if let Some(b) = self.bind_and_guard_matched_candidate(block, var_extent,
279-
arm_blocks, candidate) {
287+
if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
280288
block = b;
281289
} else {
282290
// if None is returned, then any remaining candidates
@@ -309,7 +317,7 @@ impl<H:Hair> Builder<H> {
309317
candidate))
310318
})
311319
.collect();
312-
self.match_candidates(span, var_extent, arm_blocks, applicable_candidates, target_block);
320+
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
313321
}
314322
}
315323

@@ -327,16 +335,15 @@ impl<H:Hair> Builder<H> {
327335
/// MIR).
328336
fn bind_and_guard_matched_candidate(&mut self,
329337
mut block: BasicBlock,
330-
var_extent: H::CodeExtent,
331338
arm_blocks: &mut ArmBlocks,
332339
candidate: Candidate<H>)
333340
-> Option<BasicBlock> {
334-
debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})",
335-
block, var_extent, candidate);
341+
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
342+
block, candidate);
336343

337344
debug_assert!(candidate.match_pairs.is_empty());
338345

339-
self.bind_matched_candidate(block, var_extent, candidate.bindings);
346+
self.bind_matched_candidate(block, candidate.bindings);
340347

341348
let arm_block = arm_blocks.blocks[candidate.arm_index];
342349

@@ -356,26 +363,16 @@ impl<H:Hair> Builder<H> {
356363

357364
fn bind_matched_candidate(&mut self,
358365
block: BasicBlock,
359-
var_extent: H::CodeExtent,
360366
bindings: Vec<Binding<H>>) {
361-
debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})",
362-
block, var_extent, bindings);
367+
debug!("bind_matched_candidate(block={:?}, bindings={:?})",
368+
block, bindings);
363369

364370
// Assign each of the bindings. This may trigger moves out of the candidate.
365371
for binding in bindings {
366-
// Create a variable for the `var_id` being bound. In the
367-
// case where there are multiple patterns for a single
368-
// arm, it may already exist.
369-
let var_index = if !self.var_indices.contains_key(&binding.var_id) {
370-
self.declare_binding(var_extent,
371-
binding.mutability,
372-
binding.name,
373-
binding.var_id,
374-
binding.var_ty,
375-
binding.span)
376-
} else {
377-
self.var_indices[&binding.var_id]
378-
};
372+
// Find the variable for the `var_id` being bound. It
373+
// should have been created by a previous call to
374+
// `declare_bindings`.
375+
let var_index = self.var_indices[&binding.var_id];
379376

380377
let rvalue = match binding.binding_mode {
381378
BindingMode::ByValue =>

src/librustc_mir/build/stmt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<H:Hair> Builder<H> {
4040
StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => {
4141
this.in_scope(remainder_scope, block, |this| {
4242
unpack!(block = this.in_scope(init_scope, block, |this| {
43-
this.declare_uninitialized_variables(remainder_scope, pattern);
43+
this.declare_bindings(remainder_scope, pattern);
4444
block.unit()
4545
}));
4646
this.stmts(block, stmts)

0 commit comments

Comments
 (0)