From: Yap Zhi Heng Date: Mon, 22 Sep 2025 13:29:41 +0000 (+0800) Subject: gccrs: Add HIR lowering support for rest pattern in struct patterns' AST X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54ff78002e744490ac8b900a3e6282993eb86846;p=thirdparty%2Fgcc.git 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 --- diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 842f35f288d..721d274a838 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 ebe872402ea..a2fe5d59081 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 51986763fad..0da1981928f 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> fields; - bool has_struct_pattern_etc; + bool has_rest_pattern; std::vector 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> fields, std::vector 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> 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 3bc8461c4ff..3c5e74e7aae 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 a209f80f4da..00d1bc8c33e 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> 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 e954aec309f..89b9cc6a06c 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> 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> fields) - : fields (std::move (fields)) + : fields (std::move (fields)), has_rest_pattern (false) + {} + + StructPatternElements ( + std::vector> 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 c54685d44ba..ec4c1c1d6c7 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -11430,7 +11430,7 @@ Parser::parse_struct_pattern_elems () std::vector> 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::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::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 5a2dde85e18..7b405510bb3 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 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 00000000000..3d7b0568b55 --- /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 00000000000..5f45a7c050a --- /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, ..} => {} + } +}