]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Add HIR lowering support for rest pattern in struct patterns' AST
authorYap Zhi Heng <yapzhhg@gmail.com>
Mon, 22 Sep 2025 13:29:41 +0000 (21:29 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 20:30:53 +0000 (21:30 +0100)
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 <yapzhhg@gmail.com>
gcc/rust/ast/rust-ast-collector.cc
gcc/rust/ast/rust-pattern.cc
gcc/rust/ast/rust-pattern.h
gcc/rust/expand/rust-cfg-strip.cc
gcc/rust/hir/rust-ast-lower-pattern.cc
gcc/rust/hir/tree/rust-hir-pattern.h
gcc/rust/parse/rust-parse-impl.h
gcc/rust/typecheck/rust-hir-type-check-pattern.cc
gcc/testsuite/rust/compile/issue-3929-1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-3929-2.rs [new file with mode: 0644]

index 842f35f288d5b4228b9c9aaef0d95657bf98e096..721d274a838992f5b7fd6eb74be2694fc91e38f2 100644 (file)
@@ -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 ());
index ebe872402ea8585376c3b341b3071c7fdbee8230..a2fe5d590813dd18e12f4be2d2bbc4af8d589475 100644 (file)
@@ -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";
index 51986763fad9e2c2e77553c8e7a17f13c2a4ea25..0da1981928f9c2982c8450cf27233f8ed69ccb5d 100644 (file)
@@ -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 ();
   }
index 3bc8461c4ffb8dfe4bf46a590490cc5a14098ab6..3c5e74e7aae661718880cb2710d9a2e165dc4168 100644 (file)
@@ -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 ()))
index a209f80f4dad6c9d64d244eff297c4ca1679ab6b..00d1bc8c33e4cf6ff434c681d7db43405286522a 100644 (file)
@@ -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));
 }
 
index e954aec309fab3235f3976ed78b2f0abd821b8c4..89b9cc6a06cefee4884e25d30b12782931a7f499 100644 (file)
@@ -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;
   }
 
index c54685d44ba6c2e3496a11d3fb8843506e03fd66..ec4c1c1d6c7c25ce862abc846a99015f6bc7bede 100644 (file)
@@ -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
index 5a2dde85e18adae390193dc4db5eec1d92af20dd..7b405510bb393f3a5055088e0c5821fbea0a3030 100644 (file)
@@ -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 (file)
index 0000000..3d7b056
--- /dev/null
@@ -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 (file)
index 0000000..5f45a7c
--- /dev/null
@@ -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, ..} => {}
+    }
+}