Skip to content

Commit 0fadfc5

Browse files
committed
Fix bug in matching struct patterns
Code that collects fields in struct-like patterns used to ignore wildcard patterns like `Foo{_}`. But `enter_defaults` considered struct-like patterns as default in order to overcome this (accoring to my understanding of situation). However such behaviour caused code like this: ``` enum E { Foo{f: int}, Bar } let e = Bar; match e { Foo{f: _f} => { /* do something (1) */ } _ => { /* do something (2) */ } } ``` consider pattern `Foo{f: _f}` as default. That caused inproper behaviour and even segfaults while trying to destruct `Bar` as `Foo{f: _f}`. Issues: #5625 , #5530. This patch fixes `collect_record_or_struct_fields` to split cases of single wildcard struct-like pattern and no struct-like pattern at all. Former case resolved with `enter_rec_or_struct` (and not with `enter_defaults`). Closes #5625. Closes #5530.
1 parent 1710125 commit 0fadfc5

File tree

3 files changed

+35
-24
lines changed

3 files changed

+35
-24
lines changed

src/librustc/middle/trans/_match.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ fn enter_default<'r>(bcx: @mut Block,
485485

486486
do enter_match(bcx, dm, m, col, val) |p| {
487487
match p.node {
488-
ast::pat_wild | ast::pat_tup(_) | ast::pat_struct(*) => Some(~[]),
488+
ast::pat_wild | ast::pat_tup(_) => Some(~[]),
489489
ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]),
490490
_ => None
491491
}
@@ -947,24 +947,37 @@ fn extract_vec_elems(bcx: @mut Block,
947947
ExtractedBlock { vals: elems, bcx: bcx }
948948
}
949949

950-
// NB: This function does not collect fields from struct-like enum variants.
950+
/// Checks every pattern in `m` at `col` column.
951+
/// If there are a struct pattern among them function
952+
/// returns list of all fields that are matched in these patterns.
953+
/// Function returns None if there is no struct pattern.
954+
/// Function doesn't collect fields from struct-like enum variants.
955+
/// Function can return empty list if there is only wildcard struct pattern.
951956
fn collect_record_or_struct_fields(bcx: @mut Block,
952957
m: &[Match],
953958
col: uint)
954-
-> ~[ast::ident] {
959+
-> Option<~[ast::ident]> {
955960
let mut fields: ~[ast::ident] = ~[];
961+
let mut found = false;
956962
for br in m.iter() {
957963
match br.pats[col].node {
958964
ast::pat_struct(_, ref fs, _) => {
959965
match ty::get(node_id_type(bcx, br.pats[col].id)).sty {
960-
ty::ty_struct(*) => extend(&mut fields, *fs),
966+
ty::ty_struct(*) => {
967+
extend(&mut fields, *fs);
968+
found = true;
969+
}
961970
_ => ()
962971
}
963972
}
964973
_ => ()
965974
}
966975
}
967-
return fields;
976+
if found {
977+
return Some(fields);
978+
} else {
979+
return None;
980+
}
968981

969982
fn extend(idents: &mut ~[ast::ident], field_pats: &[ast::field_pat]) {
970983
for field_pat in field_pats.iter() {
@@ -1336,22 +1349,24 @@ fn compile_submatch_continue(mut bcx: @mut Block,
13361349
// required to root any values.
13371350
assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col));
13381351

1339-
let rec_fields = collect_record_or_struct_fields(bcx, m, col);
1340-
if rec_fields.len() > 0 {
1341-
let pat_ty = node_id_type(bcx, pat_id);
1342-
let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
1343-
do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
1344-
let rec_vals = rec_fields.map(|field_name| {
1345-
let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
1346-
adt::trans_field_ptr(bcx, pat_repr, val, discr, ix)
1347-
});
1348-
compile_submatch(
1349-
bcx,
1350-
enter_rec_or_struct(bcx, dm, m, col, rec_fields, val),
1351-
vec::append(rec_vals, vals_left),
1352-
chk);
1352+
match collect_record_or_struct_fields(bcx, m, col) {
1353+
Some(ref rec_fields) => {
1354+
let pat_ty = node_id_type(bcx, pat_id);
1355+
let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
1356+
do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
1357+
let rec_vals = rec_fields.map(|field_name| {
1358+
let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
1359+
adt::trans_field_ptr(bcx, pat_repr, val, discr, ix)
1360+
});
1361+
compile_submatch(
1362+
bcx,
1363+
enter_rec_or_struct(bcx, dm, m, col, *rec_fields, val),
1364+
vec::append(rec_vals, vals_left),
1365+
chk);
1366+
}
1367+
return;
13531368
}
1354-
return;
1369+
None => {}
13551370
}
13561371

13571372
if any_tup_pat(m, col) {

src/test/run-pass/issue-5530.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
12-
1311
enum Enum {
1412
Foo { foo: uint },
1513
Bar { bar: uint }

src/test/run-pass/match-enum-struct-0.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
12-
1311
// regression test for issue #5625
1412

1513
enum E {

0 commit comments

Comments
 (0)