]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Implement compilation support for HIR::TupleStructItemsHasRest
authorYap Zhi Heng <yapzhhg@gmail.com>
Mon, 25 Aug 2025 12:33:43 +0000 (20:33 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 20:30:54 +0000 (21:30 +0100)
gcc/rust/ChangeLog:

* backend/rust-compile-pattern.cc: Add compilation support for TupleStructItemsHasRest
in CompilePatternCheckExpr(TupleStructPattern) & CompilePatternBindings(TupleStructPattern)

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
gcc/rust/backend/rust-compile-pattern.cc
gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs [new file with mode: 0644]

index 9ebb4d1dd63e87e1243e68e472dff8b312e9a3f7..9459fd618f35b1fe7efc2f163aa7d19e509a7e67 100644 (file)
@@ -358,8 +358,42 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
     {
     case HIR::TupleStructItems::HAS_REST:
       {
-       // TODO
-       rust_unreachable ();
+       HIR::TupleStructItemsHasRest &items_has_rest
+         = static_cast<HIR::TupleStructItemsHasRest &> (items);
+       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 ()));
+
+       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,
+                                                 tuple_field_index++,
+                                                 pattern->get_locus ());
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, pattern->get_locus ());
+         }
+       tuple_field_index = variant->num_fields ()
+                           - items_has_rest.get_upper_patterns ().size ();
+       for (auto &pattern : items_has_rest.get_upper_patterns ())
+         {
+           tree field_expr
+             = Backend::struct_field_expression (match_scrutinee_expr,
+                                                 tuple_field_index++,
+                                                 pattern->get_locus ());
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, pattern->get_locus ());
+         }
       }
       break;
 
@@ -738,23 +772,52 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
     {
     case HIR::TupleStructItems::HAS_REST:
       {
-       // TODO
-       rust_unreachable ();
+       HIR::TupleStructItemsHasRest &items_has_rest
+         = static_cast<HIR::TupleStructItemsHasRest &> (items);
+       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 ()));
+
+       size_t tuple_field_index = 0;
+       for (auto &pattern : items_has_rest.get_lower_patterns ())
+         {
+           tree binding
+             = Backend::struct_field_expression (match_scrutinee_expr,
+                                                 tuple_field_index++,
+                                                 pattern->get_locus ());
+
+           CompilePatternBindings::Compile (*pattern, binding, ctx);
+         }
+
+       tuple_field_index = variant->num_fields ()
+                           - items_has_rest.get_upper_patterns ().size ();
+
+       for (auto &pattern : items_has_rest.get_upper_patterns ())
+         {
+           tree binding
+             = Backend::struct_field_expression (match_scrutinee_expr,
+                                                 tuple_field_index++,
+                                                 pattern->get_locus ());
+
+           CompilePatternBindings::Compile (*pattern, binding, ctx);
+         }
       }
       break;
 
     case HIR::TupleStructItems::NO_REST:
       {
-       HIR::TupleStructItemsNoRest &items_no_range
+       HIR::TupleStructItemsNoRest &items_no_rest
          = static_cast<HIR::TupleStructItemsNoRest &> (items);
-
-       rust_assert (items_no_range.get_patterns ().size ()
+       rust_assert (items_no_rest.get_patterns ().size ()
                     == variant->num_fields ());
 
        if (adt->is_enum ())
          {
            size_t tuple_field_index = 0;
-           for (auto &pattern : items_no_range.get_patterns ())
+           for (auto &pattern : items_no_rest.get_patterns ())
              {
                tree payload_accessor_union
                  = Backend::struct_field_expression (match_scrutinee_expr, 1,
@@ -776,12 +839,10 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
        else
          {
            size_t tuple_field_index = 0;
-           for (auto &pattern : items_no_range.get_patterns ())
+           for (auto &pattern : items_no_rest.get_patterns ())
              {
-               tree variant_accessor = match_scrutinee_expr;
-
                tree binding
-                 = Backend::struct_field_expression (variant_accessor,
+                 = Backend::struct_field_expression (match_scrutinee_expr,
                                                      tuple_field_index++,
                                                      pattern->get_locus ());
 
diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs
new file mode 100644 (file)
index 0000000..4681acb
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    struct A (i32, i32);
+    let a = A (0, 1);
+
+    match a {
+        A (0, ..) => {},
+        _ => {}
+    }
+}
diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs
new file mode 100644 (file)
index 0000000..8d7446d
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-output "correct\r*" }
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+    struct A (i32, i32, i32);
+    let a = A (0, 1, 2);
+    let mut ret = 1;
+
+    match a {
+        A (1, ..) => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        }
+        A (0, b, ..) => { 
+            ret -= b;
+            unsafe { puts("correct\0" as *const str as *const i8) }
+        },
+        _ => {}
+    }
+
+    ret
+}
diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs
new file mode 100644 (file)
index 0000000..f433be9
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-output "correct\r*" }
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+    struct A (i32, i32, i32);
+    let a = A (0, 3, 1);
+    let mut ret = 1;
+
+    match a {
+        A (1, ..) => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        }
+        A (.., 3) => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        }
+        A (.., b) => { 
+            ret -= b;
+            unsafe { puts("correct\0" as *const str as *const i8) }
+        },
+        _ => {}
+    }
+
+    ret
+}