https://gcc.gnu.org/g:54ff78002e744490ac8b900a3e6282993eb86846

commit r16-4876-g54ff78002e744490ac8b900a3e6282993eb86846
Author: Yap Zhi Heng <[email protected]>
Date:   Mon Sep 22 21:29:41 2025 +0800

    gccrs: Add HIR lowering support for rest pattern in struct patterns' AST
    
    gcc/rust/ChangeLog:
    
            * ast/rust-pattern.h (StructPatternElements): Rename 
has_struct_pattern_etc
            to has_rest_pattern, and has_etc to has_rest to signify presense of 
rest
            patterns more clearly.
            * ast/rust-pattern.cc (StructPatternElements::as_string): Rename 
variables
            accordingly.
            * ast/rust-ast-collector.cc: Rename variables accordingly.
            * expand/rust-cfg-strip.cc: Rename variables accordingly.
            * parse/rust-parse-impl.h: Rename variable accordingly.
            * hir/tree/rust-hir-pattern.h (StructPatternElements): Add a 
boolean to track
            presense of rest pattern.
            * hir/rust-ast-lower-pattern.cc (visit(StructPattern)): Add support 
for
            lowering rest pattern to HIR.
            * typecheck/rust-hir-type-check-pattern.cc (visit(StructPattern)): 
Remove
            size check when rest pattern is present.
    
    Signed-off-by: Yap Zhi Heng <[email protected]>

Diff:
---
 gcc/rust/ast/rust-ast-collector.cc                |  2 +-
 gcc/rust/ast/rust-pattern.cc                      |  4 ++--
 gcc/rust/ast/rust-pattern.h                       | 16 ++++++++--------
 gcc/rust/expand/rust-cfg-strip.cc                 |  2 +-
 gcc/rust/hir/rust-ast-lower-pattern.cc            |  4 ++--
 gcc/rust/hir/tree/rust-hir-pattern.h              | 18 ++++++++++++++----
 gcc/rust/parse/rust-parse-impl.h                  |  6 +++---
 gcc/rust/typecheck/rust-hir-type-check-pattern.cc |  3 ++-
 gcc/testsuite/rust/compile/issue-3929-1.rs        |  9 +++++++++
 gcc/testsuite/rust/compile/issue-3929-2.rs        | 12 ++++++++++++
 10 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/gcc/rust/ast/rust-ast-collector.cc 
b/gcc/rust/ast/rust-ast-collector.cc
index 842f35f288d5..721d274a8389 100644
--- a/gcc/rust/ast/rust-ast-collector.cc
+++ b/gcc/rust/ast/rust-ast-collector.cc
@@ -2620,7 +2620,7 @@ TokenCollector::visit (StructPattern &pattern)
   if (elems.has_struct_pattern_fields ())
     {
       visit_items_joined_by_separator (elems.get_struct_pattern_fields ());
-      if (elems.has_etc ())
+      if (elems.has_rest ())
        {
          push (Rust::Token::make (COMMA, UNDEF_LOCATION));
          visit_items_as_lines (elems.get_etc_outer_attrs ());
diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc
index ebe872402ea8..a2fe5d590813 100644
--- a/gcc/rust/ast/rust-pattern.cc
+++ b/gcc/rust/ast/rust-pattern.cc
@@ -186,8 +186,8 @@ StructPatternElements::as_string () const
        str += "\n   " + field->as_string ();
     }
 
-  str += "\n  Etc: ";
-  if (has_struct_pattern_etc)
+  str += "\n  Has rest: ";
+  if (has_rest_pattern)
     str += "true";
   else
     str += "false";
diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h
index 51986763fad9..0da1981928f9 100644
--- a/gcc/rust/ast/rust-pattern.h
+++ b/gcc/rust/ast/rust-pattern.h
@@ -843,7 +843,7 @@ class StructPatternElements
   // bool has_struct_pattern_fields;
   std::vector<std::unique_ptr<StructPatternField>> fields;
 
-  bool has_struct_pattern_etc;
+  bool has_rest_pattern;
   std::vector<Attribute> struct_pattern_etc_attrs;
   // StructPatternEtc etc;
 
@@ -859,29 +859,29 @@ public:
    * no etc). */
   bool is_empty () const
   {
-    return !has_struct_pattern_fields () && !has_struct_pattern_etc;
+    return !has_struct_pattern_fields () && !has_rest_pattern;
   }
 
-  bool has_etc () const { return has_struct_pattern_etc; }
+  bool has_rest () const { return has_rest_pattern; }
 
   // Constructor for StructPatternElements with both (potentially)
   StructPatternElements (
     std::vector<std::unique_ptr<StructPatternField>> fields,
     std::vector<Attribute> etc_attrs)
-    : fields (std::move (fields)), has_struct_pattern_etc (true),
+    : fields (std::move (fields)), has_rest_pattern (true),
       struct_pattern_etc_attrs (std::move (etc_attrs))
   {}
 
   // Constructor for StructPatternElements with no StructPatternEtc
   StructPatternElements (
     std::vector<std::unique_ptr<StructPatternField>> fields)
-    : fields (std::move (fields)), has_struct_pattern_etc (false),
+    : fields (std::move (fields)), has_rest_pattern (false),
       struct_pattern_etc_attrs ()
   {}
 
   // Copy constructor with vector clone
   StructPatternElements (StructPatternElements const &other)
-    : has_struct_pattern_etc (other.has_struct_pattern_etc),
+    : has_rest_pattern (other.has_rest_pattern),
       struct_pattern_etc_attrs (other.struct_pattern_etc_attrs)
   {
     fields.reserve (other.fields.size ());
@@ -893,7 +893,7 @@ public:
   StructPatternElements &operator= (StructPatternElements const &other)
   {
     struct_pattern_etc_attrs = other.struct_pattern_etc_attrs;
-    has_struct_pattern_etc = other.has_struct_pattern_etc;
+    has_rest_pattern = other.has_rest_pattern;
 
     fields.clear ();
     fields.reserve (other.fields.size ());
@@ -938,7 +938,7 @@ public:
 
   void strip_etc ()
   {
-    has_struct_pattern_etc = false;
+    has_rest_pattern = false;
     struct_pattern_etc_attrs.clear ();
     struct_pattern_etc_attrs.shrink_to_fit ();
   }
diff --git a/gcc/rust/expand/rust-cfg-strip.cc 
b/gcc/rust/expand/rust-cfg-strip.cc
index 3bc8461c4ffb..3c5e74e7aae6 100644
--- a/gcc/rust/expand/rust-cfg-strip.cc
+++ b/gcc/rust/expand/rust-cfg-strip.cc
@@ -2349,7 +2349,7 @@ CfgStrip::visit (AST::StructPattern &pattern)
   maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ());
 
   // assuming you can strip the ".." part
-  if (elems.has_etc ())
+  if (elems.has_rest ())
     {
       expand_cfg_attrs (elems.get_etc_outer_attrs ());
       if (fails_cfg_with_expand (elems.get_etc_outer_attrs ()))
diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc 
b/gcc/rust/hir/rust-ast-lower-pattern.cc
index a209f80f4dad..00d1bc8c33e4 100644
--- a/gcc/rust/hir/rust-ast-lower-pattern.cc
+++ b/gcc/rust/hir/rust-ast-lower-pattern.cc
@@ -121,7 +121,6 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern)
     = ASTLowerPathInExpression::translate (pattern.get_path ());
 
   auto &raw_elems = pattern.get_struct_pattern_elems ();
-  rust_assert (!raw_elems.has_etc ());
 
   std::vector<std::unique_ptr<HIR::StructPatternField>> fields;
   for (auto &field : raw_elems.get_struct_pattern_fields ())
@@ -204,7 +203,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern)
                                 mappings.get_next_hir_id (crate_num),
                                 UNKNOWN_LOCAL_DEFID);
 
-  HIR::StructPatternElements elems (std::move (fields));
+  HIR::StructPatternElements elems (
+    std::move (fields), pattern.get_struct_pattern_elems ().has_rest ());
   translated = new HIR::StructPattern (mapping, *path, std::move (elems));
 }
 
diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h 
b/gcc/rust/hir/tree/rust-hir-pattern.h
index e954aec309fa..89b9cc6a06ce 100644
--- a/gcc/rust/hir/tree/rust-hir-pattern.h
+++ b/gcc/rust/hir/tree/rust-hir-pattern.h
@@ -683,6 +683,7 @@ protected:
 class StructPatternElements
 {
   std::vector<std::unique_ptr<StructPatternField>> fields;
+  bool has_rest_pattern;
 
 public:
   // Returns whether there are any struct pattern fields
@@ -692,10 +693,18 @@ public:
    * no etc). */
   bool is_empty () const { return !has_struct_pattern_fields (); }
 
+  bool has_rest () const { return has_rest_pattern; }
+
   // Constructor for StructPatternElements with both (potentially)
   StructPatternElements (
     std::vector<std::unique_ptr<StructPatternField>> fields)
-    : fields (std::move (fields))
+    : fields (std::move (fields)), has_rest_pattern (false)
+  {}
+
+  StructPatternElements (
+    std::vector<std::unique_ptr<StructPatternField>> fields,
+    bool has_rest_pattern)
+    : fields (std::move (fields)), has_rest_pattern (has_rest_pattern)
   {}
 
   // Copy constructor with vector clone
@@ -703,7 +712,8 @@ public:
   {
     fields.reserve (other.fields.size ());
     for (const auto &e : other.fields)
-      fields.push_back (e->clone_struct_pattern_field ());
+      fields.emplace_back (e->clone_struct_pattern_field ());
+    has_rest_pattern = other.has_rest_pattern;
   }
 
   // Overloaded assignment operator with vector clone
@@ -712,8 +722,8 @@ public:
     fields.clear ();
     fields.reserve (other.fields.size ());
     for (const auto &e : other.fields)
-      fields.push_back (e->clone_struct_pattern_field ());
-
+      fields.emplace_back (e->clone_struct_pattern_field ());
+    has_rest_pattern = other.has_rest_pattern;
     return *this;
   }
 
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index c54685d44ba6..ec4c1c1d6c7c 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -11430,7 +11430,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems 
()
   std::vector<std::unique_ptr<AST::StructPatternField>> fields;
 
   AST::AttrVec etc_attrs;
-  bool has_etc = false;
+  bool has_rest = false;
 
   // try parsing struct pattern fields
   const_TokenPtr t = lexer.peek_token ();
@@ -11443,7 +11443,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems 
()
        {
          lexer.skip_token ();
          etc_attrs = std::move (outer_attrs);
-         has_etc = true;
+         has_rest = true;
          break;
        }
 
@@ -11468,7 +11468,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems 
()
       t = lexer.peek_token ();
     }
 
-  if (has_etc)
+  if (has_rest)
     return AST::StructPatternElements (std::move (fields),
                                       std::move (etc_attrs));
   else
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc 
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 5a2dde85e18a..7b405510bb39 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -407,7 +407,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
       // Expects enum struct or struct struct.
       // error[E0027]: pattern does not mention fields `x`, `y`
       // error[E0026]: variant `Foo::D` does not have a field named `b`
-      if (named_fields.size () != variant->num_fields ())
+      if (!pattern.get_struct_pattern_elems ().has_rest ()
+         && named_fields.size () != variant->num_fields ())
        {
          std::map<std::string, bool> missing_names;
 
diff --git a/gcc/testsuite/rust/compile/issue-3929-1.rs 
b/gcc/testsuite/rust/compile/issue-3929-1.rs
new file mode 100644
index 000000000000..3d7b0568b55c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3929-1.rs
@@ -0,0 +1,9 @@
+// { dg-options "-w" }
+struct S();
+
+fn main() {
+    let s = S{};
+    match s {
+        S{..} => {}
+    }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3929-2.rs 
b/gcc/testsuite/rust/compile/issue-3929-2.rs
new file mode 100644
index 000000000000..5f45a7c050a5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3929-2.rs
@@ -0,0 +1,12 @@
+// { dg-options "-w" }
+struct S {
+    x: i32,
+    y: i32,
+}
+
+fn main() {
+    let s = S{x: 1, y: 2};
+    match s {
+        S{x: 1, ..} => {}
+    }
+}

Reply via email to