From: Utkarsh Bahuguna <[email protected]>

A tuple-variant pattern with `..` on an enum, such as `E::A(x, ..)`, hit
an assert in the HAS_REST branches of the check and bindings visitors,
which only knew the field layout of a struct. Read the fields of an enum
variant through the payload union, as the NO_REST branches already do.

Fixes Rust-GCC/gccrs#4978

gcc/rust/ChangeLog:

        * backend/rust-compile-pattern.cc
        (CompilePatternCheckExpr::visit): Support rest patterns in enum tuple
        variants.
        (CompilePatternBindings::visit): Likewise.

gcc/testsuite/ChangeLog:

        * rust/compile/irrefutable-struct.rs: Remove dg-ice, it compiles now.
        * rust/compile/tuple-variant-rest.rs: New test.
        * rust/execute/torture/tuple-variant-rest.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/89f57f80f3513a3d8cc92e205ef807bc6b77493c

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4978: https://github.com/Rust-GCC/gccrs/issues/4978

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4979

 gcc/rust/backend/rust-compile-pattern.cc      | 42 +++++++---
 .../rust/compile/irrefutable-struct.rs        |  7 +-
 .../rust/compile/tuple-variant-rest.rs        | 37 +++++++++
 .../execute/torture/tuple-variant-rest.rs     | 77 +++++++++++++++++++
 4 files changed, 148 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/tuple-variant-rest.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/tuple-variant-rest.rs

diff --git a/gcc/rust/backend/rust-compile-pattern.cc 
b/gcc/rust/backend/rust-compile-pattern.cc
index 309d8f195..8ba8b300b 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -416,15 +416,26 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern 
&pattern)
        size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
                              + items_has_rest.get_upper_patterns ().size ();
 
-       // enums cases shouldn't reach here
-       rust_assert (num_patterns <= variant->num_fields ()
-                    && (!adt->is_enum ()));
+       rust_assert (num_patterns <= variant->num_fields ());
+
+       tree fields_expr = match_scrutinee_expr;
+       if (adt->is_enum ())
+         {
+           // find payload union field of scrutinee
+           tree payload_ref
+             = Backend::struct_field_expression (match_scrutinee_expr, 1,
+                                                 pattern.get_locus ());
+
+           fields_expr
+             = Backend::struct_field_expression (payload_ref, variant_index,
+                                                 pattern.get_locus ());
+         }
 
        size_t tuple_field_index = 0;
        for (auto &pattern : items_has_rest.get_lower_patterns ())
          {
            tree field_expr
-             = Backend::struct_field_expression (match_scrutinee_expr,
+             = Backend::struct_field_expression (fields_expr,
                                                  tuple_field_index++,
                                                  pattern->get_locus ());
            tree check_expr_sub
@@ -438,7 +449,7 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern 
&pattern)
        for (auto &pattern : items_has_rest.get_upper_patterns ())
          {
            tree field_expr
-             = Backend::struct_field_expression (match_scrutinee_expr,
+             = Backend::struct_field_expression (fields_expr,
                                                  tuple_field_index++,
                                                  pattern->get_locus ());
            tree check_expr_sub
@@ -841,15 +852,26 @@ CompilePatternBindings::visit (HIR::TupleStructPattern 
&pattern)
        size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
                              + items_has_rest.get_upper_patterns ().size ();
 
-       // enums cases shouldn't reach here
-       rust_assert (num_patterns <= variant->num_fields ()
-                    && (!adt->is_enum ()));
+       rust_assert (num_patterns <= variant->num_fields ());
+
+       tree fields_expr = match_scrutinee_expr;
+       if (adt->is_enum ())
+         {
+           // find payload union field of scrutinee
+           tree payload_ref
+             = Backend::struct_field_expression (match_scrutinee_expr, 1,
+                                                 pattern.get_locus ());
+
+           fields_expr
+             = Backend::struct_field_expression (payload_ref, variant_index,
+                                                 pattern.get_locus ());
+         }
 
        size_t tuple_field_index = 0;
        for (auto &pattern : items_has_rest.get_lower_patterns ())
          {
            tree binding
-             = Backend::struct_field_expression (match_scrutinee_expr,
+             = Backend::struct_field_expression (fields_expr,
                                                  tuple_field_index++,
                                                  pattern->get_locus ());
 
@@ -862,7 +884,7 @@ CompilePatternBindings::visit (HIR::TupleStructPattern 
&pattern)
        for (auto &pattern : items_has_rest.get_upper_patterns ())
          {
            tree binding
-             = Backend::struct_field_expression (match_scrutinee_expr,
+             = Backend::struct_field_expression (fields_expr,
                                                  tuple_field_index++,
                                                  pattern->get_locus ());
 
diff --git a/gcc/testsuite/rust/compile/irrefutable-struct.rs 
b/gcc/testsuite/rust/compile/irrefutable-struct.rs
index feeb1b32f..6bd7ed25b 100644
--- a/gcc/testsuite/rust/compile/irrefutable-struct.rs
+++ b/gcc/testsuite/rust/compile/irrefutable-struct.rs
@@ -1,11 +1,8 @@
 #![feature(no_core)]
 #![no_core]
 
-// this test ICEs because in CompilePatternBindings::visit 
(HIR::TupleStructPattern &pattern)
-// we are missing an implementation handling 'E::T(a, .., b)' with rest 
patterns
-// once that is implemented, this test should pass
-// { dg-ice "" }
-//
+// { dg-additional-options "-w" }
+
 struct S {
     x: i32,
     y: i32,
diff --git a/gcc/testsuite/rust/compile/tuple-variant-rest.rs 
b/gcc/testsuite/rust/compile/tuple-variant-rest.rs
new file mode 100644
index 000000000..2dba18558
--- /dev/null
+++ b/gcc/testsuite/rust/compile/tuple-variant-rest.rs
@@ -0,0 +1,37 @@
+#![feature(no_core)]
+#![no_core]
+
+// A rest pattern in an enum tuple variant used to ICE in the backend.
+
+pub enum E {
+    A(i32, i32, i32),
+    B,
+}
+
+pub fn first(e: E) -> i32 {
+    match e {
+        E::A(x, ..) => x,
+        E::B => 0,
+    }
+}
+
+pub fn last(e: E) -> i32 {
+    match e {
+        E::A(.., y) => y,
+        E::B => 0,
+    }
+}
+
+pub fn ends(e: E) -> i32 {
+    match e {
+        E::A(x, .., y) => x + y,
+        E::B => 0,
+    }
+}
+
+pub fn any(e: E) -> bool {
+    match e {
+        E::A(..) => true,
+        E::B => false,
+    }
+}
diff --git a/gcc/testsuite/rust/execute/torture/tuple-variant-rest.rs 
b/gcc/testsuite/rust/execute/torture/tuple-variant-rest.rs
new file mode 100644
index 000000000..ff9572b5f
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/tuple-variant-rest.rs
@@ -0,0 +1,77 @@
+#![feature(no_core)]
+#![no_core]
+
+// A rest pattern in an enum tuple variant used to ICE in the backend. Check
+// that the fields around `..` are read from the right variant.
+
+enum E {
+    A(i32, i32, i32),
+    B(i32, i32, i32),
+}
+
+fn first(e: E) -> i32 {
+    match e {
+        E::A(x, ..) => x,
+        E::B(..) => 100,
+    }
+}
+
+fn last(e: E) -> i32 {
+    match e {
+        E::A(.., y) => y,
+        E::B(..) => 100,
+    }
+}
+
+fn ends(e: E) -> i32 {
+    match e {
+        E::A(x, .., y) => x * 100 + y,
+        E::B(..) => 100,
+    }
+}
+
+fn last_of_b(e: E) -> i32 {
+    match e {
+        E::B(.., z) => z,
+        E::A(..) => 200,
+    }
+}
+
+fn starts_with_seven(e: E) -> i32 {
+    match e {
+        E::A(7, ..) => 1,
+        E::A(..) => 2,
+        E::B(..) => 3,
+    }
+}
+
+fn main() -> i32 {
+    if first(E::A(7, 11, 13)) != 7 {
+        return 1;
+    }
+    if last(E::A(7, 11, 13)) != 13 {
+        return 2;
+    }
+    if ends(E::A(7, 11, 13)) != 713 {
+        return 3;
+    }
+    if first(E::B(7, 11, 13)) != 100 {
+        return 4;
+    }
+    if last_of_b(E::B(17, 19, 23)) != 23 {
+        return 5;
+    }
+    if last_of_b(E::A(17, 19, 23)) != 200 {
+        return 6;
+    }
+    if starts_with_seven(E::A(7, 11, 13)) != 1 {
+        return 7;
+    }
+    if starts_with_seven(E::A(8, 11, 13)) != 2 {
+        return 8;
+    }
+    if starts_with_seven(E::B(7, 11, 13)) != 3 {
+        return 9;
+    }
+    0
+}

base-commit: ba0aef5d4f6cfbc5f63c86c8c21aad35b23d82e6
-- 
2.55.0

Reply via email to