]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Implement rest pattern support for slice patterns
authorYap Zhi Heng <yapzhhg@gmail.com>
Mon, 11 Aug 2025 13:51:11 +0000 (21:51 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 19:58:40 +0000 (20:58 +0100)
This patch adds support for compiling rest patterns present in slice patterns
(e.g. `[1, .., 2]`). 006t.original output from compiling match-slicepattern-slice-2.rs
for first 2 match arms:

...
  if (RUSTTMP.3.len > 1 && *NON_LVALUE_EXPR <RUSTTMP.3.data> == 1)
    {
      {
                struct () RUSTTMP.4;
        {
                    struct () RUSTTMP.5;
          {
           ..
          }
        }
        goto <D.139>;
      }
    }
  if ((RUSTTMP.3.len > 1 && *NON_LVALUE_EXPR <RUSTTMP.3.data> == 0) && *(RUSTTMP.3.data + (sizetype) (RUSTTMP.3.len + 18446744073709551615) * 4) == 0)
    {
      {
                struct () RUSTTMP.6;
        {
                    struct () RUSTTMP.7;
          {
          }
        }
        goto <D.139>;
      }
    }
...

gcc/rust/ChangeLog:

* hir/tree/rust-hir-pattern.h: Add SlicePatternItems base class and
SlicePatternItemsNoRest/SlicePatternItemsHasRest derived classes.
Update SlicePattern to hold patterns using the new classes.
* hir/tree/rust-hir-full-decls.h: Declare new classes.
* hir/tree/rust-hir.cc: Add visits for new classes.
* hir/tree/rust-hir-visitor.h: Add visits for new classes.
* hir/tree/rust-hir-visitor.cc: Implement visits for new classes.
* hir/rust-hir-dump.h: Add visits for new classes.
* hir/rust-hir-dump.cc: Implement Dump::visit for new classes.
* hir/rust-ast-lower-base.h: Declare new lower_slice_pattern_no_rest/has_rest
methods.
* hir/rust-ast-lower-base.cc: Implement lower_slice_pattern_no_rest/has_rest
to lower AST slice pattern items to HIR.
* hir/rust-ast-lower-pattern.cc: Update ASTLoweringPattern::visit for
SlicePattern to use new lowering methods.
* backend/rust-compile-pattern.cc: Update CompilePatternCheckExpr::visit
and CompilePatternBindings::visit for SlicePattern to handle
SlicePatternItemsNoRest/HasRest.
* checks/errors/borrowck/rust-bir-builder-pattern.cc: Update
PatternBindingBuilder::visit for SlicePattern to iterate members correctly.
* checks/errors/borrowck/rust-bir-builder-struct.h: Add visits for new
classes.
* checks/errors/borrowck/rust-function-collector.h: Add visits for new
classes.
* checks/errors/rust-const-checker.h: Add visits for new classes.
* checks/errors/rust-const-checker.cc: Implement empty visits for new classes.
* checks/errors/rust-hir-pattern-analysis.h: Add visits for new classes.
* checks/errors/rust-hir-pattern-analysis.cc: Implement empty visits for new
classes.
* checks/errors/rust-unsafe-checker.h: Add visits for new classes.
* checks/errors/rust-unsafe-checker.cc: Implement empty visits for new
classes.
* typecheck/rust-hir-type-check-pattern.cc: Update TypeCheckPattern::visit
for SlicePattern to handle SlicePatternItemsNoRest/HasRest.

gcc/testsuite/ChangeLog:

* rust/compile/slice_rest_pattern.rs: Removed -fsyntax-only.

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
24 files changed:
gcc/rust/backend/rust-compile-pattern.cc
gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
gcc/rust/checks/errors/borrowck/rust-function-collector.h
gcc/rust/checks/errors/rust-const-checker.cc
gcc/rust/checks/errors/rust-const-checker.h
gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
gcc/rust/checks/errors/rust-hir-pattern-analysis.h
gcc/rust/checks/errors/rust-unsafe-checker.cc
gcc/rust/checks/errors/rust-unsafe-checker.h
gcc/rust/hir/rust-ast-lower-base.cc
gcc/rust/hir/rust-ast-lower-base.h
gcc/rust/hir/rust-ast-lower-pattern.cc
gcc/rust/hir/rust-hir-dump.cc
gcc/rust/hir/rust-hir-dump.h
gcc/rust/hir/tree/rust-hir-full-decls.h
gcc/rust/hir/tree/rust-hir-pattern.h
gcc/rust/hir/tree/rust-hir-visitor.cc
gcc/rust/hir/tree/rust-hir-visitor.h
gcc/rust/hir/tree/rust-hir.cc
gcc/rust/typecheck/rust-hir-type-check-pattern.cc
gcc/testsuite/rust/compile/slice_rest_pattern.rs
gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs [new file with mode: 0644]

index 577f8de9c93bd9018b1354c8768e773552f363d7..e29dc92ea49b44ba944cef4f1f96a068298a5a27 100644 (file)
@@ -534,25 +534,14 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
               || lookup->get_kind () == TyTy::TypeKind::SLICE
               || lookup->get_kind () == TyTy::REF);
 
-  size_t array_element_index = 0;
+  // function ptr that points to either array_index_expression or
+  // slice_index_expression depending on the scrutinee's type
+  tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
   switch (lookup->get_kind ())
     {
     case TyTy::TypeKind::ARRAY:
-      for (auto &pattern_member : pattern.get_items ())
-       {
-         tree array_index_tree
-           = Backend::size_constant_expression (array_element_index++);
-         tree element_expr
-           = Backend::array_index_expression (match_scrutinee_expr,
-                                              array_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 ());
-       }
+      scrutinee_index_expr_func = Backend::array_index_expression;
       break;
     case TyTy::TypeKind::SLICE:
       rust_sorry_at (
@@ -562,25 +551,81 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
     case TyTy::TypeKind::REF:
       {
        rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
+       scrutinee_index_expr_func = Backend::slice_index_expression;
        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 ());
+       // for slices, generate a dynamic size comparison expression tree
+       // because size checking is done at runtime.
+       switch (pattern.get_items ().get_item_type ())
+         {
+         case HIR::SlicePatternItems::ItemType::NO_REST:
+           {
+             auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
+               pattern.get_items ());
+             check_expr = Backend::comparison_expression (
+               ComparisonOperator::EQUAL, size_field,
+               build_int_cst (size_type_node, items.get_patterns ().size ()),
+               pattern.get_locus ());
+           }
+           break;
+         case HIR::SlicePatternItems::ItemType::HAS_REST:
+           {
+             auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
+               pattern.get_items ());
+             auto pattern_min_cap = items.get_lower_patterns ().size ()
+                                    + items.get_upper_patterns ().size ();
+             check_expr = Backend::comparison_expression (
+               ComparisonOperator::GREATER_OR_EQUAL, size_field,
+               build_int_cst (size_type_node, pattern_min_cap),
+               pattern.get_locus ());
+           }
+           break;
+         }
+      }
+      break;
+    default:
+      rust_unreachable ();
+    }
+
+  rust_assert (scrutinee_index_expr_func != nullptr);
 
-       // Then compare each element in the slice pattern
-       for (auto &pattern_member : pattern.get_items ())
+  // Generate tree to compare every element within array/slice
+  size_t element_index = 0;
+  switch (pattern.get_items ().get_item_type ())
+    {
+    case HIR::SlicePatternItems::ItemType::NO_REST:
+      {
+       auto &items
+         = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+       for (auto &pattern_member : items.get_patterns ())
          {
-           tree slice_index_tree
-             = Backend::size_constant_expression (array_element_index++);
+           tree index_tree
+             = Backend::size_constant_expression (element_index++);
            tree element_expr
-             = Backend::slice_index_expression (match_scrutinee_expr,
-                                                slice_index_tree,
-                                                pattern.get_locus ());
+             = scrutinee_index_expr_func (match_scrutinee_expr, 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;
+      }
+    case HIR::SlicePatternItems::ItemType::HAS_REST:
+      {
+       auto &items
+         = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+       for (auto &pattern_member : items.get_lower_patterns ())
+         {
+           tree index_tree
+             = Backend::size_constant_expression (element_index++);
+           tree element_expr
+             = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+                                          pattern.get_locus ());
            tree check_expr_sub
              = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
                                                  ctx);
@@ -588,10 +633,71 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
              ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
              check_expr_sub, pattern.get_locus ());
          }
+
+       // handle codegen for upper patterns differently for both types
+       switch (lookup->get_kind ())
+         {
+         case TyTy::TypeKind::ARRAY:
+           {
+             // for array type scrutinee, we can simply get the capacity as a
+             // const and calculate how many elements to skip
+             auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+             auto cap_tree = array_ty->get_capacity ()->get_value ();
+             size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+             element_index = cap_wi - items.get_upper_patterns ().size ();
+             for (auto &pattern_member : items.get_upper_patterns ())
+               {
+                 tree index_tree
+                   = Backend::size_constant_expression (element_index++);
+                 tree element_expr
+                   = scrutinee_index_expr_func (match_scrutinee_expr,
+                                                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;
+         case TyTy::TypeKind::REF:
+           {
+             // for slice type scrutinee, size is dyanamic, so number of
+             // elements to skip is calculated during runtime
+             tree slice_size
+               = Backend::struct_field_expression (match_scrutinee_expr, 1,
+                                                   pattern.get_locus ());
+             tree upper_patterns_size = Backend::size_constant_expression (
+               items.get_upper_patterns ().size ());
+             tree index_tree = Backend::arithmetic_or_logical_expression (
+               ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+               upper_patterns_size, pattern.get_locus ());
+             for (auto &pattern_member : items.get_upper_patterns ())
+               {
+                 tree element_expr
+                   = scrutinee_index_expr_func (match_scrutinee_expr,
+                                                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 ());
+                 index_tree = Backend::arithmetic_or_logical_expression (
+                   ArithmeticOrLogicalOperator::ADD, index_tree,
+                   Backend::size_constant_expression (1),
+                   pattern.get_locus ());
+               }
+           }
+           break;
+         default:
+           rust_unreachable ();
+         }
       }
       break;
-    default:
-      rust_unreachable ();
     }
 }
 
@@ -932,43 +1038,121 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern)
               || lookup->get_kind () == TyTy::TypeKind::SLICE
               || lookup->get_kind () == TyTy::REF);
 
-  size_t array_element_index = 0;
+  // function ptr that points to either array_index_expression or
+  // slice_index_expression depending on the scrutinee's type
+  tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
   switch (lookup->get_kind ())
     {
     case TyTy::TypeKind::ARRAY:
-      for (auto &pattern_member : pattern.get_items ())
-       {
-         tree array_index_tree
-           = Backend::size_constant_expression (array_element_index++);
-         tree element_expr
-           = Backend::array_index_expression (match_scrutinee_expr,
-                                              array_index_tree,
-                                              pattern.get_locus ());
-         CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
-       }
+      scrutinee_index_expr_func = Backend::array_index_expression;
       break;
     case TyTy::TypeKind::SLICE:
-      rust_sorry_at (
-       pattern.get_locus (),
-       "SlicePattern matching against non-ref slices are not yet supported");
+      rust_sorry_at (pattern.get_locus (),
+                    "SlicePattern matching against non-ref slices are "
+                    "not yet supported");
       break;
     case TyTy::TypeKind::REF:
+      scrutinee_index_expr_func = Backend::slice_index_expression;
+      break;
+    default:
+      rust_unreachable ();
+    }
+
+  rust_assert (scrutinee_index_expr_func != nullptr);
+
+  size_t element_index = 0;
+
+  switch (pattern.get_items ().get_item_type ())
+    {
+    case HIR::SlicePatternItems::ItemType::NO_REST:
       {
-       for (auto &pattern_member : pattern.get_items ())
+       auto &items
+         = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+       for (auto &pattern_member : items.get_patterns ())
          {
-           tree slice_index_tree
-             = Backend::size_constant_expression (array_element_index++);
+           tree index_tree
+             = Backend::size_constant_expression (element_index++);
            tree element_expr
-             = Backend::slice_index_expression (match_scrutinee_expr,
-                                                slice_index_tree,
-                                                pattern.get_locus ());
+             = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+                                          pattern.get_locus ());
            CompilePatternBindings::Compile (*pattern_member, element_expr,
                                             ctx);
          }
-       break;
       }
-    default:
-      rust_unreachable ();
+      break;
+    case HIR::SlicePatternItems::ItemType::HAS_REST:
+      {
+       auto &items
+         = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+       for (auto &pattern_member : items.get_lower_patterns ())
+         {
+           tree index_tree
+             = Backend::size_constant_expression (element_index++);
+           tree element_expr
+             = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+                                          pattern.get_locus ());
+           CompilePatternBindings::Compile (*pattern_member, element_expr,
+                                            ctx);
+         }
+
+       // handle codegen for upper patterns differently for both types
+       switch (lookup->get_kind ())
+         {
+         case TyTy::TypeKind::ARRAY:
+           {
+             auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+             auto cap_tree = array_ty->get_capacity ()->get_value ();
+             size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+             element_index = cap_wi - items.get_upper_patterns ().size ();
+             for (auto &pattern_member : items.get_upper_patterns ())
+               {
+                 tree index_tree
+                   = Backend::size_constant_expression (element_index++);
+                 tree element_expr
+                   = scrutinee_index_expr_func (match_scrutinee_expr,
+                                                index_tree,
+                                                pattern.get_locus ());
+                 CompilePatternBindings::Compile (*pattern_member,
+                                                  element_expr, ctx);
+               }
+           }
+           break;
+         case TyTy::TypeKind::SLICE:
+           rust_sorry_at (pattern.get_locus (),
+                          "SlicePattern matching against non-ref slices are "
+                          "not yet supported");
+           break;
+         case TyTy::TypeKind::REF:
+           {
+             tree slice_size
+               = Backend::struct_field_expression (match_scrutinee_expr, 1,
+                                                   pattern.get_locus ());
+             tree upper_patterns_size = Backend::size_constant_expression (
+               items.get_upper_patterns ().size ());
+             tree index_tree = Backend::arithmetic_or_logical_expression (
+               ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+               upper_patterns_size, pattern.get_locus ());
+             for (auto &pattern_member : items.get_upper_patterns ())
+               {
+                 tree element_expr
+                   = scrutinee_index_expr_func (match_scrutinee_expr,
+                                                index_tree,
+                                                pattern.get_locus ());
+                 CompilePatternBindings::Compile (*pattern_member,
+                                                  element_expr, ctx);
+                 index_tree = Backend::arithmetic_or_logical_expression (
+                   ArithmeticOrLogicalOperator::ADD, index_tree,
+                   Backend::size_constant_expression (1),
+                   pattern.get_locus ());
+               }
+           }
+           break;
+         default:
+           rust_unreachable ();
+         }
+      }
+      break;
     }
 }
 
index 18f9584a4f0e4bc0ed1d9d6e0c98d79de2a9b907..e78d7505094b5593a4e5bb3ab60e32a10e0ad457 100644 (file)
@@ -70,11 +70,34 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
     return ty->as<TyTy::SliceType> ()->get_element_type ();
   });
 
-  // Regions are unchnaged.
+  // Regions are unchanged.
 
-  for (auto &item : pattern.get_items ())
+  switch (pattern.get_items ().get_item_type ())
     {
-      item->accept_vis (*this);
+    case HIR::SlicePatternItems::NO_REST:
+      {
+       auto &items
+         = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+       for (auto &member : items.get_patterns ())
+         {
+           member->accept_vis (*this);
+         }
+       break;
+      }
+    case HIR::SlicePatternItems::HAS_REST:
+      {
+       auto &items
+         = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+       for (auto &member : items.get_lower_patterns ())
+         {
+           member->accept_vis (*this);
+         }
+       for (auto &member : items.get_upper_patterns ())
+         {
+           member->accept_vis (*this);
+         }
+       break;
+      }
     }
 }
 
index f05dd6ceb1ba2506cf43eae0be90f549ed4ecc4f..6cb87c7568acb7704c7940313c763238805552b7 100644 (file)
@@ -246,6 +246,14 @@ protected:
     rust_unreachable ();
   }
   void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); }
+  void visit (HIR::SlicePatternItemsNoRest &tuple_items) override
+  {
+    rust_unreachable ();
+  }
+  void visit (HIR::SlicePatternItemsHasRest &tuple_items) override
+  {
+    rust_unreachable ();
+  }
   void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); }
   void visit (HIR::AltPattern &pattern) override { rust_unreachable (); }
   void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); }
index f4a11702a854c0e719f017e60848f588a72e61f8..63f2a95f4bfdaeb407cd89183cc6c9483145c5db 100644 (file)
@@ -176,6 +176,8 @@ public:
   void visit (HIR::TuplePatternItemsNoRest &tuple_items) override {}
   void visit (HIR::TuplePatternItemsHasRest &tuple_items) override {}
   void visit (HIR::TuplePattern &pattern) override {}
+  void visit (HIR::SlicePatternItemsNoRest &tuple_items) override {}
+  void visit (HIR::SlicePatternItemsHasRest &tuple_items) override {}
   void visit (HIR::SlicePattern &pattern) override {}
   void visit (HIR::AltPattern &pattern) override {}
   void visit (HIR::EmptyStmt &stmt) override {}
index 845e5b68187f3a4fe13a0c265aa96b0e8c9e6887..782d6940bbeeee0f51749977530f875493784240 100644 (file)
@@ -836,6 +836,14 @@ void
 ConstChecker::visit (TuplePattern &)
 {}
 
+void
+ConstChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+ConstChecker::visit (SlicePatternItemsHasRest &)
+{}
+
 void
 ConstChecker::visit (SlicePattern &)
 {}
index 66138bdc851af8706b1fbac99987c09808bbd54c..d464b7b9fce5d66a712785996f644d8a8d831791 100644 (file)
@@ -186,6 +186,8 @@ private:
   virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
   virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
   virtual void visit (TuplePattern &pattern) override;
+  virtual void visit (SlicePatternItemsNoRest &items) override;
+  virtual void visit (SlicePatternItemsHasRest &items) override;
   virtual void visit (SlicePattern &pattern) override;
   virtual void visit (AltPattern &pattern) override;
   virtual void visit (EmptyStmt &stmt) override;
index 7fe7f029f2aab0710c150b85e5f15f80061e158f..290087c573f1d879e5343ad563c47bce3349972b 100644 (file)
@@ -663,6 +663,14 @@ void
 PatternChecker::visit (TuplePattern &)
 {}
 
+void
+PatternChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+PatternChecker::visit (SlicePatternItemsHasRest &)
+{}
+
 void
 PatternChecker::visit (SlicePattern &)
 {}
index 6aefaeca63fc4418eaefb5d68b128858d222f199..d75e900f2be44a633fc99e1f6e2d6e7cb8037346 100644 (file)
@@ -159,6 +159,8 @@ private:
   virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
   virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
   virtual void visit (TuplePattern &pattern) override;
+  virtual void visit (SlicePatternItemsNoRest &items) override;
+  virtual void visit (SlicePatternItemsHasRest &items) override;
   virtual void visit (SlicePattern &pattern) override;
   virtual void visit (AltPattern &pattern) override;
   virtual void visit (EmptyStmt &stmt) override;
index 41ed698db7789d642d16a3e106bdaffcefde5c7b..607d20fa11f7a857dc35a7c9c4de3c03b3eda2e0 100644 (file)
@@ -949,6 +949,14 @@ void
 UnsafeChecker::visit (TuplePattern &)
 {}
 
+void
+UnsafeChecker::visit (SlicePatternItemsNoRest &)
+{}
+
+void
+UnsafeChecker::visit (SlicePatternItemsHasRest &)
+{}
+
 void
 UnsafeChecker::visit (SlicePattern &)
 {}
index 4c884ad6b04777db663d7bc06180449797665c11..420668f46ed8d64508b5070a7d265bf1da18a02b 100644 (file)
@@ -167,6 +167,8 @@ private:
   virtual void visit (TuplePatternItemsNoRest &tuple_items) override;
   virtual void visit (TuplePatternItemsHasRest &tuple_items) override;
   virtual void visit (TuplePattern &pattern) override;
+  virtual void visit (SlicePatternItemsNoRest &items) override;
+  virtual void visit (SlicePatternItemsHasRest &items) override;
   virtual void visit (SlicePattern &pattern) override;
   virtual void visit (AltPattern &pattern) override;
   virtual void visit (EmptyStmt &stmt) override;
index f3ae3ce71a3dbd5a894c1525abf3a07889e92638..e32918e8e85b9673c37d8d62ef0f2c9e877cc435 100644 (file)
@@ -906,6 +906,41 @@ ASTLoweringBase::lower_tuple_pattern_ranged (
                                       std::move (upper_patterns)));
 }
 
+std::unique_ptr<HIR::SlicePatternItems>
+ASTLoweringBase::lower_slice_pattern_no_rest (
+  AST::SlicePatternItemsNoRest &pattern)
+{
+  std::vector<std::unique_ptr<HIR::Pattern>> patterns;
+  patterns.reserve (pattern.get_patterns ().size ());
+  for (auto &p : pattern.get_patterns ())
+    patterns.emplace_back (ASTLoweringPattern::translate (*p));
+
+  return std::unique_ptr<HIR::SlicePatternItems> (
+    new HIR::SlicePatternItemsNoRest (std::move (patterns)));
+}
+
+std::unique_ptr<HIR::SlicePatternItems>
+ASTLoweringBase::lower_slice_pattern_has_rest (
+  AST::SlicePatternItemsHasRest &pattern)
+{
+  std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns;
+  lower_patterns.reserve (pattern.get_lower_patterns ().size ());
+  std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns;
+  upper_patterns.reserve (pattern.get_upper_patterns ().size ());
+
+  for (auto &p : pattern.get_lower_patterns ())
+    lower_patterns.emplace_back (
+      std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p)));
+
+  for (auto &p : pattern.get_upper_patterns ())
+    upper_patterns.emplace_back (
+      std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p)));
+
+  return std::unique_ptr<HIR::SlicePatternItems> (
+    new HIR::SlicePatternItemsHasRest (std::move (lower_patterns),
+                                      std::move (upper_patterns)));
+}
+
 std::unique_ptr<HIR::RangePatternBound>
 ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound)
 {
index e86aacb216a6cf5ce34de9cabf0ca4fcc04c41ad..a188e1785268ffda7a46a4758f5fdbe677cd4e6c 100644 (file)
@@ -322,6 +322,12 @@ protected:
   std::unique_ptr<TuplePatternItems>
   lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern);
 
+  std::unique_ptr<SlicePatternItems>
+  lower_slice_pattern_no_rest (AST::SlicePatternItemsNoRest &pattern);
+
+  std::unique_ptr<SlicePatternItems>
+  lower_slice_pattern_has_rest (AST::SlicePatternItemsHasRest &pattern);
+
   std::unique_ptr<HIR::RangePatternBound>
   lower_range_pattern_bound (AST::RangePatternBound &bound);
 
index f1b3ba8cfad97f364f6a49e198190b44129cf5f1..6933c2dca834e2515d25bac75b2523723eed3cae 100644 (file)
@@ -322,23 +322,22 @@ ASTLoweringPattern::visit (AST::ReferencePattern &pattern)
 void
 ASTLoweringPattern::visit (AST::SlicePattern &pattern)
 {
-  std::vector<std::unique_ptr<HIR::Pattern>> items;
+  std::unique_ptr<HIR::SlicePatternItems> items;
 
   switch (pattern.get_items ().get_pattern_type ())
     {
     case AST::SlicePatternItems::SlicePatternItemType::NO_REST:
       {
-       AST::SlicePatternItemsNoRest &ref
+       auto &ref
          = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ());
-       for (auto &p : ref.get_patterns ())
-         items.emplace_back (ASTLoweringPattern::translate (*p));
+       items = ASTLoweringBase::lower_slice_pattern_no_rest (ref);
       }
       break;
     case AST::SlicePatternItems::SlicePatternItemType::HAS_REST:
       {
-       rust_error_at (pattern.get_locus (),
-                      "lowering of slice patterns with rest elements are not "
-                      "supported yet");
+       auto &ref
+         = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ());
+       items = ASTLoweringBase::lower_slice_pattern_has_rest (ref);
       }
       break;
     }
index b5c2bcf24fecb404368dd8b7d68453e1374bff33..49ce143789995f20e02ef13ab2a31b2265b4d21c 100644 (file)
@@ -2362,12 +2362,29 @@ Dump::visit (TuplePattern &e)
   end ("TuplePattern");
 }
 
+void
+Dump::visit (SlicePatternItemsNoRest &e)
+{
+  begin ("SlicePatternItemsNoRest");
+  visit_collection ("patterns", e.get_patterns ());
+  end ("SlicePatternItemsNoRest");
+}
+
+void
+Dump::visit (SlicePatternItemsHasRest &e)
+{
+  begin ("SlicePatternItemsHasRest");
+  visit_collection ("lower_patterns", e.get_lower_patterns ());
+  visit_collection ("upper_patterns", e.get_upper_patterns ());
+  end ("SlicePatternItemsHasRest");
+}
+
 void
 Dump::visit (SlicePattern &e)
 {
   begin ("SlicePattern");
   do_mappings (e.get_mappings ());
-  visit_collection ("items", e.get_items ());
+  visit_field ("items", e.get_items ());
   end ("SlicePattern");
 }
 
index 0202210db8734f71f4bfeed33b6b354199cdeab3..4dfc8859393f3e5339d068be00d6070ba2426f5e 100644 (file)
@@ -230,7 +230,11 @@ private:
   virtual void visit (TuplePatternItemsNoRest &) override;
   virtual void visit (TuplePatternItemsHasRest &) override;
   virtual void visit (TuplePattern &) override;
+
+  virtual void visit (SlicePatternItemsNoRest &) override;
+  virtual void visit (SlicePatternItemsHasRest &) override;
   virtual void visit (SlicePattern &) override;
+
   virtual void visit (AltPattern &) override;
 
   virtual void visit (EmptyStmt &) override;
index b52ccb402860d53eff3290c6ec8f5b6d6685b07b..aec2f362e44e0e43e72ab8ef2832c5bff33da573 100644 (file)
@@ -206,6 +206,8 @@ class TuplePatternItems;
 class TuplePatternItemsNoRest;
 class TuplePatternItemsHasRest;
 class TuplePattern;
+class SlicePatternItemsNoRest;
+class SlicePatternItemsHasRest;
 class SlicePattern;
 class AltPattern;
 
index 2a2965875f89bf6e8582ce250f4d880d1ed2cab3..e3581dc5c8c8c0634b7ddb7a08c52f6e5d9f144f 100644 (file)
@@ -1241,10 +1241,161 @@ protected:
   }
 };
 
+// Base abstract class representing SlicePattern patterns
+class SlicePatternItems : public PatternItems
+{
+public:
+  // Unique pointer custom clone function
+  std::unique_ptr<SlicePatternItems> clone_slice_pattern_items () const
+  {
+    return std::unique_ptr<SlicePatternItems> (clone_pattern_items_impl ());
+  }
+
+protected:
+  // pure virtual clone implementation
+  virtual SlicePatternItems *clone_pattern_items_impl () const override = 0;
+};
+
+// Class representing patterns within a SlicePattern, without a rest pattern
+class SlicePatternItemsNoRest : public SlicePatternItems
+{
+  std::vector<std::unique_ptr<Pattern>> patterns;
+
+public:
+  SlicePatternItemsNoRest (std::vector<std::unique_ptr<Pattern>> patterns)
+    : patterns (std::move (patterns))
+  {}
+
+  // Copy constructor with vector clone
+  SlicePatternItemsNoRest (SlicePatternItemsNoRest const &other)
+  {
+    patterns.reserve (other.patterns.size ());
+    for (const auto &e : other.patterns)
+      patterns.push_back (e->clone_pattern ());
+  }
+
+  // Overloaded assignment operator to vector clone
+  SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest const &other)
+  {
+    patterns.clear ();
+    patterns.reserve (other.patterns.size ());
+    for (const auto &e : other.patterns)
+      patterns.push_back (e->clone_pattern ());
+
+    return *this;
+  }
+
+  // move constructors
+  SlicePatternItemsNoRest (SlicePatternItemsNoRest &&other) = default;
+  SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest &&other)
+    = default;
+
+  std::string as_string () const override;
+
+  void accept_vis (HIRFullVisitor &vis) override;
+
+  ItemType get_item_type () const override { return ItemType::NO_REST; }
+
+  std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; }
+  const std::vector<std::unique_ptr<Pattern>> &get_patterns () const
+  {
+    return patterns;
+  }
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  SlicePatternItemsNoRest *clone_pattern_items_impl () const override
+  {
+    return new SlicePatternItemsNoRest (*this);
+  }
+};
+
+// Class representing patterns within a SlicePattern, with a rest pattern
+// included
+class SlicePatternItemsHasRest : public SlicePatternItems
+{
+  std::vector<std::unique_ptr<Pattern>> lower_patterns;
+  std::vector<std::unique_ptr<Pattern>> upper_patterns;
+
+public:
+  SlicePatternItemsHasRest (
+    std::vector<std::unique_ptr<Pattern>> lower_patterns,
+    std::vector<std::unique_ptr<Pattern>> upper_patterns)
+    : lower_patterns (std::move (lower_patterns)),
+      upper_patterns (std::move (upper_patterns))
+  {}
+
+  // Copy constructor with vector clone
+  SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other)
+  {
+    lower_patterns.reserve (other.lower_patterns.size ());
+    for (const auto &e : other.lower_patterns)
+      lower_patterns.push_back (e->clone_pattern ());
+
+    upper_patterns.reserve (other.upper_patterns.size ());
+    for (const auto &e : other.upper_patterns)
+      upper_patterns.push_back (e->clone_pattern ());
+  }
+
+  // Overloaded assignment operator to clone
+  SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest const &other)
+  {
+    lower_patterns.clear ();
+    lower_patterns.reserve (other.lower_patterns.size ());
+    for (const auto &e : other.lower_patterns)
+      lower_patterns.push_back (e->clone_pattern ());
+
+    lower_patterns.clear ();
+    upper_patterns.reserve (other.upper_patterns.size ());
+    for (const auto &e : other.upper_patterns)
+      upper_patterns.push_back (e->clone_pattern ());
+
+    return *this;
+  }
+
+  // move constructors
+  SlicePatternItemsHasRest (SlicePatternItemsHasRest &&other) = default;
+  SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest &&other)
+    = default;
+
+  std::string as_string () const override;
+
+  void accept_vis (HIRFullVisitor &vis) override;
+
+  ItemType get_item_type () const override { return ItemType::HAS_REST; }
+
+  std::vector<std::unique_ptr<Pattern>> &get_lower_patterns ()
+  {
+    return lower_patterns;
+  }
+  const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const
+  {
+    return lower_patterns;
+  }
+
+  std::vector<std::unique_ptr<Pattern>> &get_upper_patterns ()
+  {
+    return upper_patterns;
+  }
+  const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const
+  {
+    return upper_patterns;
+  }
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  SlicePatternItemsHasRest *clone_pattern_items_impl () const override
+  {
+    return new SlicePatternItemsHasRest (*this);
+  }
+};
+
 // HIR node representing patterns that can match slices and arrays
 class SlicePattern : public Pattern
 {
-  std::vector<std::unique_ptr<Pattern>> items;
+  std::unique_ptr<SlicePatternItems> items;
   location_t locus;
   Analysis::NodeMapping mappings;
 
@@ -1252,30 +1403,23 @@ public:
   std::string as_string () const override;
 
   SlicePattern (Analysis::NodeMapping mappings,
-               std::vector<std::unique_ptr<Pattern>> items, location_t locus)
+               std::unique_ptr<SlicePatternItems> items, location_t locus)
     : items (std::move (items)), locus (locus), mappings (mappings)
   {}
 
-  // Copy constructor with vector clone
+  // Copy constructor requires clone
   SlicePattern (SlicePattern const &other)
-    : locus (other.locus), mappings (other.mappings)
-  {
-    items.reserve (other.items.size ());
-    for (const auto &e : other.items)
-      items.push_back (e->clone_pattern ());
-  }
+    : items (other.items->clone_slice_pattern_items ()), locus (other.locus),
+      mappings (other.mappings)
+  {}
 
   // Overloaded assignment operator to vector clone
   SlicePattern &operator= (SlicePattern const &other)
   {
+    items = other.items->clone_slice_pattern_items ();
     locus = other.locus;
     mappings = other.mappings;
 
-    items.clear ();
-    items.reserve (other.items.size ());
-    for (const auto &e : other.items)
-      items.push_back (e->clone_pattern ());
-
     return *this;
   }
 
@@ -1283,11 +1427,8 @@ public:
   SlicePattern (SlicePattern &&other) = default;
   SlicePattern &operator= (SlicePattern &&other) = default;
 
-  std::vector<std::unique_ptr<Pattern>> &get_items () { return items; }
-  const std::vector<std::unique_ptr<Pattern>> &get_items () const
-  {
-    return items;
-  }
+  SlicePatternItems &get_items () { return *items; }
+  const SlicePatternItems &get_items () const { return *items; }
 
   location_t get_locus () const override { return locus; }
 
index 15db3f0d6dfe6cd147ea2c9bf4775f803bd5d747..1e201a5541e4f1ec97cd93fd0b13193c95ada0f4 100644 (file)
@@ -1067,11 +1067,26 @@ DefaultHIRVisitor::walk (TuplePattern &pattern)
   pattern.get_items ().accept_vis (*this);
 }
 
+void
+DefaultHIRVisitor::walk (SlicePatternItemsNoRest &items)
+{
+  for (auto &pattern : items.get_patterns ())
+    pattern->accept_vis (*this);
+}
+
+void
+DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items)
+{
+  for (auto &lower : items.get_lower_patterns ())
+    lower->accept_vis (*this);
+  for (auto &upper : items.get_upper_patterns ())
+    upper->accept_vis (*this);
+}
+
 void
 DefaultHIRVisitor::walk (SlicePattern &pattern)
 {
-  for (auto &item : pattern.get_items ())
-    item->accept_vis (*this);
+  pattern.get_items ().accept_vis (*this);
 }
 
 void
index d0bb484b41eee6a7d87ec4a6cca9b163fc8429f4..77760b0141dc897172ab341e5683bfbd9c9be5c5 100644 (file)
@@ -138,6 +138,8 @@ public:
   virtual void visit (TuplePatternItemsNoRest &tuple_items) = 0;
   virtual void visit (TuplePatternItemsHasRest &tuple_items) = 0;
   virtual void visit (TuplePattern &pattern) = 0;
+  virtual void visit (SlicePatternItemsNoRest &items) = 0;
+  virtual void visit (SlicePatternItemsHasRest &items) = 0;
   virtual void visit (SlicePattern &pattern) = 0;
   virtual void visit (AltPattern &pattern) = 0;
   virtual void visit (EmptyStmt &stmt) = 0;
@@ -311,6 +313,8 @@ public:
   virtual void visit (TuplePatternItemsNoRest &node) override { walk (node); }
   virtual void visit (TuplePatternItemsHasRest &node) override { walk (node); }
   virtual void visit (TuplePattern &node) override { walk (node); }
+  virtual void visit (SlicePatternItemsNoRest &node) override { walk (node); }
+  virtual void visit (SlicePatternItemsHasRest &node) override { walk (node); }
   virtual void visit (SlicePattern &node) override { walk (node); }
   virtual void visit (AltPattern &node) override { walk (node); }
   virtual void visit (EmptyStmt &node) override { walk (node); }
@@ -444,6 +448,8 @@ protected:
   virtual void walk (TuplePatternItemsNoRest &) final;
   virtual void walk (TuplePatternItemsHasRest &) final;
   virtual void walk (TuplePattern &) final;
+  virtual void walk (SlicePatternItemsNoRest &) final;
+  virtual void walk (SlicePatternItemsHasRest &) final;
   virtual void walk (SlicePattern &) final;
   virtual void walk (AltPattern &) final;
   virtual void walk (EmptyStmt &) final;
@@ -593,6 +599,9 @@ public:
   virtual void visit (TuplePatternItemsNoRest &) override {}
   virtual void visit (TuplePatternItemsHasRest &) override {}
   virtual void visit (TuplePattern &) override {}
+
+  virtual void visit (SlicePatternItemsNoRest &) override {}
+  virtual void visit (SlicePatternItemsHasRest &) override {}
   virtual void visit (SlicePattern &) override {}
   virtual void visit (AltPattern &) override {}
 
index 39c0e2e1c292293bd2ce2bb4efb70b6fa00c12b1..7aad4ef2730396cedb6bd45f6cb85aad4bcce8de 100644 (file)
@@ -2386,11 +2386,11 @@ RangePatternBoundLiteral::as_string () const
 }
 
 std::string
-SlicePattern::as_string () const
+SlicePatternItemsNoRest::as_string () const
 {
-  std::string str ("SlicePattern: ");
+  std::string str;
 
-  for (const auto &pattern : items)
+  for (const auto &pattern : patterns)
     {
       str += "\n " + pattern->as_string ();
     }
@@ -2398,6 +2398,46 @@ SlicePattern::as_string () const
   return str;
 }
 
+std::string
+SlicePatternItemsHasRest::as_string () const
+{
+  std::string str;
+
+  str += "\n Lower patterns: ";
+  if (lower_patterns.empty ())
+    {
+      str += "none";
+    }
+  else
+    {
+      for (const auto &lower : lower_patterns)
+       {
+         str += "\n  " + lower->as_string ();
+       }
+    }
+
+  str += "\n Upper patterns: ";
+  if (upper_patterns.empty ())
+    {
+      str += "none";
+    }
+  else
+    {
+      for (const auto &upper : upper_patterns)
+       {
+         str += "\n  " + upper->as_string ();
+       }
+    }
+
+  return str;
+}
+
+std::string
+SlicePattern::as_string () const
+{
+  return "SlicePattern: " + items->as_string ();
+}
+
 std::string
 AltPattern::as_string () const
 {
@@ -4505,6 +4545,18 @@ TuplePattern::accept_vis (HIRFullVisitor &vis)
   vis.visit (*this);
 }
 
+void
+SlicePatternItemsNoRest::accept_vis (HIRFullVisitor &vis)
+{
+  vis.visit (*this);
+}
+
+void
+SlicePatternItemsHasRest::accept_vis (HIRFullVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 SlicePattern::accept_vis (HIRFullVisitor &vis)
 {
index b34679eb6b40f94750c3da55855f7eb72aaa054a..5a2dde85e18adae390193dc4db5eec1d92af20dd 100644 (file)
@@ -651,14 +651,44 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
            break;
          }
        auto cap_wi = wi::to_wide (cap).to_uhwi ();
-       if (cap_wi != pattern.get_items ().size ())
+
+       // size check during compile time
+       switch (pattern.get_items ().get_item_type ())
          {
-           rust_error_at (pattern.get_locus (), ErrorCode::E0527,
-                          "pattern requires %lu elements but array has %lu",
-                          (unsigned long) pattern.get_items ().size (),
-                          (unsigned long) cap_wi);
+         case HIR::SlicePatternItems::ItemType::NO_REST:
+           {
+             auto &ref = static_cast<HIR::SlicePatternItemsNoRest &> (
+               pattern.get_items ());
+             if (cap_wi != ref.get_patterns ().size ())
+               {
+                 rust_error_at (
+                   pattern.get_locus (), ErrorCode::E0527,
+                   "pattern requires %lu elements but array has %lu",
+                   (unsigned long) ref.get_patterns ().size (),
+                   (unsigned long) cap_wi);
+                 break;
+               }
+           }
+           break;
+         case HIR::SlicePatternItems::ItemType::HAS_REST:
+           {
+             auto &ref = static_cast<HIR::SlicePatternItemsHasRest &> (
+               pattern.get_items ());
+             auto pattern_min_cap = ref.get_lower_patterns ().size ()
+                                    + ref.get_upper_patterns ().size ();
+
+             if (cap_wi < pattern_min_cap)
+               {
+                 rust_error_at (
+                   pattern.get_locus (), ErrorCode::E0528,
+                   "pattern requires at least %lu elements but array has %lu",
+                   (unsigned long) pattern_min_cap, (unsigned long) cap_wi);
+                 break;
+               }
+           }
            break;
          }
+
        break;
       }
     case TyTy::SLICE:
@@ -694,10 +724,32 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
   infered->set_ref (pattern.get_mappings ().get_hirid ());
 
   // Type check every item in the SlicePattern against parent's element ty
-  // TODO update this after adding support for RestPattern in SlicePattern
-  for (const auto &item : pattern.get_items ())
+  switch (pattern.get_items ().get_item_type ())
     {
-      TypeCheckPattern::Resolve (*item, parent_element_ty);
+    case HIR::SlicePatternItems::ItemType::NO_REST:
+      {
+       auto &ref
+         = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+       for (const auto &pattern_member : ref.get_patterns ())
+         {
+           TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+         }
+       break;
+      }
+    case HIR::SlicePatternItems::ItemType::HAS_REST:
+      {
+       auto &ref
+         = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+       for (const auto &pattern_member : ref.get_lower_patterns ())
+         {
+           TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+         }
+       for (const auto &pattern_member : ref.get_upper_patterns ())
+         {
+           TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
+         }
+       break;
+      }
     }
 }
 
index c27a8dd777e4443676557eb75da30b42a583fc2c..bb3c414173a350e873b1d82b21f5b798239f0c69 100644 (file)
@@ -1,5 +1,4 @@
-// { dg-options "-fsyntax-only" }
-fn foo(a: &[u32]) {
+pub fn foo(a: &[u32]) {
     match a {
         [first, ..] => {}
         [.., last] => {}
diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs
new file mode 100644 (file)
index 0000000..c6e7762
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-output "correct\r*" }
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+    let a = [0, 4, 5, 6, 1];
+    let mut ret = 1;
+
+    match a {
+        [1, .., b] => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        }
+        [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
+}
diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs
new file mode 100644 (file)
index 0000000..2fdffbb
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-output "correct\r*" }
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn main() -> i32 {
+    let arr = [0, 4, 5, 6, 1];
+    let a: &[i32] = &arr;
+    let mut ret = 1;
+
+    match a {
+        [1, .., b] => {
+            /* should not take this path */
+            unsafe { puts("wrong\0" as *const str as *const i8) }
+        }
+        [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
+}