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