Skip to content

Commit 6a88415

Browse files
committed
auto merge of #8544 : dim-an/rust/fix-match-pipes, r=pcwalton
Pointers to bound variables shouldn't be stored before checking pattern, otherwise piped patterns can conflict with each other (issue #6338). Closes #6338.
2 parents 6791021 + f4b8854 commit 6a88415

File tree

2 files changed

+94
-20
lines changed

2 files changed

+94
-20
lines changed

src/librustc/middle/trans/_match.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,17 @@ struct ArmData<'self> {
399399
bindings_map: @BindingsMap
400400
}
401401

402+
/**
403+
* Info about Match.
404+
* If all `pats` are matched then arm `data` will be executed.
405+
* As we proceed `bound_ptrs` are filled with pointers to values to be bound,
406+
* these pointers are stored in llmatch variables just before executing `data` arm.
407+
*/
402408
#[deriving(Clone)]
403409
struct Match<'self> {
404410
pats: ~[@ast::pat],
405-
data: ArmData<'self>
411+
data: ArmData<'self>,
412+
bound_ptrs: ~[(ident, ValueRef)]
406413
}
407414

408415
impl<'self> Repr for Match<'self> {
@@ -447,14 +454,13 @@ fn expand_nested_bindings<'r>(bcx: @mut Block,
447454
br.pats.slice(col + 1u,
448455
br.pats.len())));
449456

450-
let binding_info =
451-
br.data.bindings_map.get(&path_to_ident(path));
452-
453-
Store(bcx, val, binding_info.llmatch);
454-
Match {
457+
let mut res = Match {
455458
pats: pats,
456-
data: br.data.clone()
457-
}
459+
data: br.data.clone(),
460+
bound_ptrs: br.bound_ptrs.clone()
461+
};
462+
res.bound_ptrs.push((path_to_ident(path), val));
463+
res
458464
}
459465
_ => (*br).clone(),
460466
}
@@ -496,21 +502,20 @@ fn enter_match<'r>(bcx: @mut Block,
496502
br.pats.slice(col + 1u, br.pats.len()));
497503

498504
let this = br.pats[col];
505+
let mut bound_ptrs = br.bound_ptrs.clone();
499506
match this.node {
500507
ast::pat_ident(_, ref path, None) => {
501508
if pat_is_binding(dm, this) {
502-
let binding_info =
503-
br.data.bindings_map.get(
504-
&path_to_ident(path));
505-
Store(bcx, val, binding_info.llmatch);
509+
bound_ptrs.push((path_to_ident(path), val));
506510
}
507511
}
508512
_ => {}
509513
}
510514

511515
result.push(Match {
512516
pats: pats,
513-
data: br.data.clone()
517+
data: br.data.clone(),
518+
bound_ptrs: bound_ptrs
514519
});
515520
}
516521
None => ()
@@ -1294,18 +1299,14 @@ fn store_non_ref_bindings(bcx: @mut Block,
12941299

12951300
fn insert_lllocals(bcx: @mut Block,
12961301
bindings_map: &BindingsMap,
1297-
binding_mode: IrrefutablePatternBindingMode,
12981302
add_cleans: bool) -> @mut Block {
12991303
/*!
13001304
* For each binding in `data.bindings_map`, adds an appropriate entry into
13011305
* the `fcx.lllocals` map. If add_cleans is true, then adds cleanups for
13021306
* the bindings.
13031307
*/
13041308

1305-
let llmap = match binding_mode {
1306-
BindLocal => bcx.fcx.lllocals,
1307-
BindArgument => bcx.fcx.llargs
1308-
};
1309+
let llmap = bcx.fcx.lllocals;
13091310

13101311
for (&ident, &binding_info) in bindings_map.iter() {
13111312
let llval = match binding_info.trmode {
@@ -1358,7 +1359,7 @@ fn compile_guard(bcx: @mut Block,
13581359
bcx = store_non_ref_bindings(bcx,
13591360
data.bindings_map,
13601361
Some(&mut temp_cleanups));
1361-
bcx = insert_lllocals(bcx, data.bindings_map, BindLocal, false);
1362+
bcx = insert_lllocals(bcx, data.bindings_map, false);
13621363

13631364
let val = unpack_result!(bcx, {
13641365
do with_scope_result(bcx, guard_expr.info(),
@@ -1418,6 +1419,10 @@ fn compile_submatch(bcx: @mut Block,
14181419
}
14191420
if m[0].pats.len() == 0u {
14201421
let data = &m[0].data;
1422+
for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
1423+
let llmatch = data.bindings_map.get(ident).llmatch;
1424+
Store(bcx, *value_ptr, llmatch);
1425+
}
14211426
match data.arm.guard {
14221427
Some(guard_expr) => {
14231428
bcx = compile_guard(bcx,
@@ -1843,6 +1848,7 @@ fn trans_match_inner(scope_cx: @mut Block,
18431848
matches.push(Match {
18441849
pats: ~[*p],
18451850
data: arm_data.clone(),
1851+
bound_ptrs: ~[],
18461852
});
18471853
}
18481854
}
@@ -1875,7 +1881,7 @@ fn trans_match_inner(scope_cx: @mut Block,
18751881
}
18761882

18771883
// insert bindings into the lllocals map and add cleanups
1878-
bcx = insert_lllocals(bcx, arm_data.bindings_map, BindLocal, true);
1884+
bcx = insert_lllocals(bcx, arm_data.bindings_map, true);
18791885

18801886
bcx = controlflow::trans_block(bcx, &arm_data.arm.body, dest);
18811887
bcx = trans_block_cleanups(bcx, block_cleanups(arm_data.bodycx));
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn test1() {
12+
// from issue 6338
13+
match ((1, ~"a"), (2, ~"b")) {
14+
((1, a), (2, b)) | ((2, b), (1, a)) => {
15+
assert_eq!(a, ~"a");
16+
assert_eq!(b, ~"b");
17+
},
18+
_ => fail!(),
19+
}
20+
}
21+
22+
fn test2() {
23+
match (1, 2, 3) {
24+
(1, a, b) | (2, b, a) => {
25+
assert_eq!(a, 2);
26+
assert_eq!(b, 3);
27+
},
28+
_ => fail!(),
29+
}
30+
}
31+
32+
fn test3() {
33+
match (1, 2, 3) {
34+
(1, ref a, ref b) | (2, ref b, ref a) => {
35+
assert_eq!(*a, 2);
36+
assert_eq!(*b, 3);
37+
},
38+
_ => fail!(),
39+
}
40+
}
41+
42+
fn test4() {
43+
match (1, 2, 3) {
44+
(1, a, b) | (2, b, a) if a == 2 => {
45+
assert_eq!(a, 2);
46+
assert_eq!(b, 3);
47+
},
48+
_ => fail!(),
49+
}
50+
}
51+
52+
fn test5() {
53+
match (1, 2, 3) {
54+
(1, ref a, ref b) | (2, ref b, ref a) if *a == 2 => {
55+
assert_eq!(*a, 2);
56+
assert_eq!(*b, 3);
57+
},
58+
_ => fail!(),
59+
}
60+
}
61+
62+
fn main() {
63+
test1();
64+
test2();
65+
test3();
66+
test4();
67+
test5();
68+
}

0 commit comments

Comments
 (0)