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, ..} => {} + } +}
