about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDmitry Ermolov <epdmitry@yandex.ru>2013-08-06 22:43:57 +0400
committerDmitry Ermolov <epdmitry@yandex.ru>2013-08-07 00:04:28 +0400
commit0fadfc5fb7de47f0ffcb55a8bbfe0a75c2a4dbee (patch)
treee1f486734fd0c05d86a85a8f9b2dfbc13807e0d6
parent1710125f673fe8ca2f1ab76074ca26d6f6acd720 (diff)
downloadrust-0fadfc5fb7de47f0ffcb55a8bbfe0a75c2a4dbee.tar.gz
rust-0fadfc5fb7de47f0ffcb55a8bbfe0a75c2a4dbee.zip
Fix bug in `match`ing 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.
-rw-r--r--src/librustc/middle/trans/_match.rs55
-rw-r--r--src/test/run-pass/issue-5530.rs2
-rw-r--r--src/test/run-pass/match-enum-struct-0.rs2
3 files changed, 35 insertions, 24 deletions
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index e5d45d6ca21..327d2e698c1 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -485,7 +485,7 @@ fn enter_default<'r>(bcx: @mut Block,
 
     do enter_match(bcx, dm, m, col, val) |p| {
         match p.node {
-          ast::pat_wild | ast::pat_tup(_) | ast::pat_struct(*) => Some(~[]),
+          ast::pat_wild | ast::pat_tup(_) => Some(~[]),
           ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]),
           _ => None
         }
@@ -947,24 +947,37 @@ fn extract_vec_elems(bcx: @mut Block,
     ExtractedBlock { vals: elems, bcx: bcx }
 }
 
-// NB: This function does not collect fields from struct-like enum variants.
+/// Checks every pattern in `m` at `col` column.
+/// If there are a struct pattern among them function
+/// returns list of all fields that are matched in these patterns.
+/// Function returns None if there is no struct pattern.
+/// Function doesn't collect fields from struct-like enum variants.
+/// Function can return empty list if there is only wildcard struct pattern.
 fn collect_record_or_struct_fields(bcx: @mut Block,
                                        m: &[Match],
                                        col: uint)
-                                    -> ~[ast::ident] {
+                                    -> Option<~[ast::ident]> {
     let mut fields: ~[ast::ident] = ~[];
+    let mut found = false;
     for br in m.iter() {
         match br.pats[col].node {
           ast::pat_struct(_, ref fs, _) => {
             match ty::get(node_id_type(bcx, br.pats[col].id)).sty {
-              ty::ty_struct(*) => extend(&mut fields, *fs),
+              ty::ty_struct(*) => {
+                   extend(&mut fields, *fs);
+                   found = true;
+              }
               _ => ()
             }
           }
           _ => ()
         }
     }
-    return fields;
+    if found {
+        return Some(fields);
+    } else {
+        return None;
+    }
 
     fn extend(idents: &mut ~[ast::ident], field_pats: &[ast::field_pat]) {
         for field_pat in field_pats.iter() {
@@ -1336,22 +1349,24 @@ fn compile_submatch_continue(mut bcx: @mut Block,
     // required to root any values.
     assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col));
 
-    let rec_fields = collect_record_or_struct_fields(bcx, m, col);
-    if rec_fields.len() > 0 {
-        let pat_ty = node_id_type(bcx, pat_id);
-        let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
-        do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
-            let rec_vals = rec_fields.map(|field_name| {
-                let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
-                adt::trans_field_ptr(bcx, pat_repr, val, discr, ix)
-            });
-            compile_submatch(
-                bcx,
-                enter_rec_or_struct(bcx, dm, m, col, rec_fields, val),
-                vec::append(rec_vals, vals_left),
-                chk);
+    match collect_record_or_struct_fields(bcx, m, col) {
+        Some(ref rec_fields) => {
+            let pat_ty = node_id_type(bcx, pat_id);
+            let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
+            do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
+                let rec_vals = rec_fields.map(|field_name| {
+                        let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
+                        adt::trans_field_ptr(bcx, pat_repr, val, discr, ix)
+                        });
+                compile_submatch(
+                        bcx,
+                        enter_rec_or_struct(bcx, dm, m, col, *rec_fields, val),
+                        vec::append(rec_vals, vals_left),
+                        chk);
+            }
+            return;
         }
-        return;
+        None => {}
     }
 
     if any_tup_pat(m, col) {
diff --git a/src/test/run-pass/issue-5530.rs b/src/test/run-pass/issue-5530.rs
index 002435fcb36..8e55ad90c70 100644
--- a/src/test/run-pass/issue-5530.rs
+++ b/src/test/run-pass/issue-5530.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
-
 enum Enum {
     Foo { foo: uint },
     Bar { bar: uint }
diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs
index 5b72eb7aa73..365729ec860 100644
--- a/src/test/run-pass/match-enum-struct-0.rs
+++ b/src/test/run-pass/match-enum-struct-0.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
-
 // regression test for issue #5625
 
 enum E {