]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Implement compilation for SlicePattern against SliceType scrutinee
authorYap Zhi Heng <yapzhhg@gmail.com>
Wed, 23 Jul 2025 00:24:18 +0000 (08:24 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:58 +0000 (16:36 +0200)
006t.original output from compiling testsuite/rust/compile/match-slicepattern-slice.rs:

...
  RUSTTMP.3 = slice;
  if (RUSTTMP.3.len == 1 && *(RUSTTMP.3.data + 0 * 4) == 1)
    {
      {
                struct () RUSTTMP.4;
        {

        }
        goto <D.129>;
      }
    }
  if (RUSTTMP.3.len == 2 && *(RUSTTMP.3.data + 1 * 4) == 2)
    {
      {
                struct () RUSTTMP.5;
        {

        }
        goto <D.129>;
      }
    }
  if (1)
    {
      {
                struct () RUSTTMP.6;
        {

        }
        goto <D.129>;
      }
    }
  <D.129>:;
...

gcc/rust/ChangeLog:

* rust-backend.h: New slice_index_expression function.
* rust-gcc.cc: Implementation of slice_index_expression to generate tree node for
accessing slice elements.
* backend/rust-compile-pattern.cc: Implement SlicePattern check expression & binding
compilation against SliceType scrutinee.

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

index e00de4f467f30f9e595a6a2fa923c54489a46e4e..fe6592174382ee799b0785247ab940b6d2c19355 100644 (file)
@@ -555,7 +555,38 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
     case TyTy::TypeKind::SLICE:
       rust_sorry_at (
        pattern.get_locus (),
-       "SlicePattern matching against slices are not yet supported");
+       "SlicePattern matching against non-ref slices are not yet supported");
+      break;
+    case TyTy::TypeKind::REF:
+      {
+       rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
+       tree size_field
+         = Backend::struct_field_expression (match_scrutinee_expr, 1,
+                                             pattern.get_locus ());
+
+       // First compare the size
+       check_expr = Backend::comparison_expression (
+         ComparisonOperator::EQUAL, size_field,
+         build_int_cst (size_type_node, pattern.get_items ().size ()),
+         pattern.get_locus ());
+
+       // Then compare each element in the slice pattern
+       for (auto &pattern_member : pattern.get_items ())
+         {
+           tree slice_index_tree
+             = Backend::size_constant_expression (array_element_index++);
+           tree element_expr
+             = Backend::slice_index_expression (match_scrutinee_expr,
+                                                slice_index_tree,
+                                                pattern.get_locus ());
+           tree check_expr_sub
+             = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
+                                                 ctx);
+           check_expr = Backend::arithmetic_or_logical_expression (
+             ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+             check_expr_sub, pattern.get_locus ());
+         }
+      }
       break;
     default:
       rust_unreachable ();
@@ -917,8 +948,23 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern)
     case TyTy::TypeKind::SLICE:
       rust_sorry_at (
        pattern.get_locus (),
-       "SlicePattern matching against slices are not yet supported");
+       "SlicePattern matching against non-ref slices are not yet supported");
       break;
+    case TyTy::TypeKind::REF:
+      {
+       for (auto &pattern_member : pattern.get_items ())
+         {
+           tree slice_index_tree
+             = Backend::size_constant_expression (array_element_index++);
+           tree element_expr
+             = Backend::slice_index_expression (match_scrutinee_expr,
+                                                slice_index_tree,
+                                                pattern.get_locus ());
+           CompilePatternBindings::Compile (*pattern_member, element_expr,
+                                            ctx);
+         }
+       break;
+      }
     default:
       rust_unreachable ();
     }
index 8a77d96de83596f48e48b0fb92f293e449a7a6b2..205eb2b7146590c5d6fcb0098f843f628209d96f 100644 (file)
@@ -245,6 +245,10 @@ tree array_initializer (tree, tree, tree, tree, tree, tree *, location_t);
 // fixed-length array, not a slice.
 tree array_index_expression (tree array, tree index, location_t);
 
+// Return an expresison for SLICE[INDEX] as an l-value.  SLICE is represented
+// with a DST.
+tree slice_index_expression (tree slice, tree index, location_t);
+
 // Create an expression for a call to FN with ARGS, taking place within
 // caller CALLER.
 tree call_expression (tree fn, const std::vector<tree> &args, tree static_chain,
index c5fda5c7a9ca8bf96a51127ecce35db8d1fa00d3..0f9ccfb9c81a2beb84b427f45d4f5c5830f2de0e 100644 (file)
@@ -1504,6 +1504,34 @@ array_index_expression (tree array_tree, tree index_tree, location_t location)
   return ret;
 }
 
+// Return an expression representing SLICE[INDEX]
+
+tree
+slice_index_expression (tree slice_tree, tree index_tree, location_t location)
+{
+  if (error_operand_p (slice_tree) || error_operand_p (index_tree))
+    return error_mark_node;
+
+  // A slice is created in TyTyResolvecompile::create_slice_type_record
+  // For example:
+  //   &[i32] is turned directly into a struct { i32* data, usize len };
+  //   [i32] is also turned into struct { i32* data, usize len }
+
+  // it should have RS_DST_FLAG set to 1
+  rust_assert (RS_DST_FLAG_P (TREE_TYPE (slice_tree)));
+
+  tree data_field = struct_field_expression (slice_tree, 0, location);
+  tree data_field_deref = build_fold_indirect_ref_loc (location, data_field);
+
+  tree element_type = TREE_TYPE (data_field_deref);
+  tree data_pointer = TREE_OPERAND (data_field_deref, 0);
+  rust_assert (POINTER_TYPE_P (TREE_TYPE (data_pointer)));
+  tree data_offset_expr
+    = Rust::pointer_offset_expression (data_pointer, index_tree, location);
+
+  return build1_loc (location, INDIRECT_REF, element_type, data_offset_expr);
+}
+
 // Create an expression for a call to FN_EXPR with FN_ARGS.
 tree
 call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr,
diff --git a/gcc/testsuite/rust/compile/match-slicepattern-slice.rs b/gcc/testsuite/rust/compile/match-slicepattern-slice.rs
new file mode 100644 (file)
index 0000000..cc33d93
--- /dev/null
@@ -0,0 +1,10 @@
+fn main() {
+    let arr = [1, 2];
+    let slice: &[i32] = &arr;
+
+    match slice {
+        [1] => {},
+        [_, 2] => {},
+        _ => {}
+    }
+}
\ No newline at end of file
diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs
new file mode 100644 (file)
index 0000000..3ed0b64
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-output "correct\r*" }
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+    let arr = [0, 1];
+    let a: &[i32] = &arr;
+    let mut ret = 1;
+
+    match a {
+        [0, 0] => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        },
+        [0, b] => {
+            ret -= b;
+            unsafe { puts("correct\0" as *const str as *const i8) }
+        },
+        _ => {}
+    }
+
+    ret
+}