https://gcc.gnu.org/g:7e7390c1c96e1befd84cb707d395a2c0ba68e7ae
commit r17-4102-g7e7390c1c96e1befd84cb707d395a2c0ba68e7ae Author: Owen Avery <[email protected]> Date: Wed Aug 5 00:47:00 2026 -0400 gccrs: Partially support x@.. in SlicePattern Slice patterns with bound rest patterns still aren't supported in type checking and compilation to GENERIC. gcc/rust/ChangeLog: * backend/rust-compile-pattern.cc (CompilePatternBindings::visit (SlicePattern)): Assert that the rest pattern isn't bound (currently unsupported). * checks/errors/borrowck/rust-bir-builder-pattern.cc (PatternBindingBuilder::visit (SlicePattern)): Handle bound rest pattern. * checks/errors/rust-ast-validation.cc (ASTValidation::visit (AST::SlicePattern)): Likewise. * hir/rust-ast-lower-pattern.cc (ASTLoweringPattern::visit (AST::SlicePattern)): Likewise. * hir/rust-hir-dump.cc (Dump::visit (SlicePatternItemsHasRest)): Likewise. * hir/tree/rust-hir-pattern.h (SlicePatternItemsHasRest::rest_bind): New member variable. (SlicePatternItemsHasRest::SlicePatternItemsHasRest): Initialize rest_bind. (SlicePatternItemsHasRest::operator=): Likewise. (SlicePatternItemsHasRest::has_rest_bind): New member function. (SlicePatternItemsHasRest::get_rest_bind): Likewise. * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk (SlicePatternItemsHasRest)): Handle bound rest pattern. * hir/tree/rust-hir.cc (SlicePatternItemsHasRest::to_string): Likewise. * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit (SlicePattern)): Assert that the rest pattern isn't bound (currently unsupported). gcc/testsuite/ChangeLog: * rust/compile/slice_rest_pattern_2.rs: New test. Signed-off-by: Owen Avery <[email protected]> Diff: --- gcc/rust/backend/rust-compile-pattern.cc | 4 +++ .../errors/borrowck/rust-bir-builder-pattern.cc | 4 +++ gcc/rust/checks/errors/rust-ast-validation.cc | 21 +++++++++--- gcc/rust/hir/rust-ast-lower-pattern.cc | 37 +++++++++++++++++++--- gcc/rust/hir/rust-hir-dump.cc | 2 ++ gcc/rust/hir/tree/rust-hir-pattern.h | 26 +++++++++++++-- gcc/rust/hir/tree/rust-hir-visitor.cc | 2 ++ gcc/rust/hir/tree/rust-hir.cc | 6 ++++ gcc/rust/typecheck/rust-hir-type-check-pattern.cc | 4 +++ gcc/testsuite/rust/compile/slice_rest_pattern_2.rs | 11 +++++++ 10 files changed, 107 insertions(+), 10 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index e2f54d7ac624..19f5bc4ed887 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -1233,6 +1233,10 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern) { auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + + // TODO: support rest_bind (c in [a, b, c @ ..]) + rust_assert (!items.has_rest_bind ()); + for (auto &pattern_member : items.get_lower_patterns ()) { tree index_tree diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc index e78d7505094b..5bd061470199 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -92,6 +92,10 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern) { member->accept_vis (*this); } + if (items.has_rest_bind ()) + { + items.get_rest_bind ().accept_vis (*this); + } for (auto &member : items.get_upper_patterns ()) { member->accept_vis (*this); diff --git a/gcc/rust/checks/errors/rust-ast-validation.cc b/gcc/rust/checks/errors/rust-ast-validation.cc index e3262b947cb4..b2825fb2c958 100644 --- a/gcc/rust/checks/errors/rust-ast-validation.cc +++ b/gcc/rust/checks/errors/rust-ast-validation.cc @@ -205,14 +205,27 @@ ASTValidation::visit (AST::SlicePattern &pattern) // for nicer errors bool had_rest = false; + auto note_rest = [&] (location_t locus) { + if (had_rest) + rust_error_at (locus, "%<..%> can only be used once per slice pattern"); + had_rest = true; + }; + for (auto &pat : pattern.get_patterns ()) { if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest) { - if (had_rest) - rust_error_at (pat->get_locus (), - "%<..%> can only be used once per slice pattern"); - had_rest = true; + note_rest (pat->get_locus ()); + } + else if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier) + { + auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat); + if (ident_pat.has_subpattern ()) + { + auto &ident_sub_pat = ident_pat.get_subpattern (); + if (ident_sub_pat.get_pattern_kind () == AST::Pattern::Kind::Rest) + note_rest (ident_sub_pat.get_locus ()); + } } } } diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index b19a6411d2e9..17d4dc981e1d 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -353,17 +353,46 @@ void ASTLoweringPattern::visit (AST::SlicePattern &pattern) { tl::optional<size_t> rest_index; + tl::optional<HIR::IdentifierPattern> rest_bind; std::vector<std::unique_ptr<AST::Pattern>> &sub_patterns = pattern.get_patterns (); + // need this earlier than usual + // since we might need to produce rest_bind + auto crate_num = mappings.get_current_crate (); + for (size_t i = 0; i < sub_patterns.size (); i++) { auto &pat = sub_patterns[i]; - if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest) + + // ASTValidation verified there's only one Rest pattern + // so we can break once we find the first one + if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier) + { + auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat); + if (ident_pat.has_subpattern ()) + { + if (ident_pat.get_subpattern ().get_pattern_kind () + == AST::Pattern::Kind::Rest) + { + Analysis::NodeMapping rest_bind_mapping ( + crate_num, ident_pat.get_node_id (), + mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); + + rest_bind = HIR::IdentifierPattern ( + std::move (rest_bind_mapping), ident_pat.get_ident (), + ident_pat.get_locus (), ident_pat.get_is_ref (), + ident_pat.get_is_mut () ? Mutability::Mut + : Mutability::Imm); + rest_index = i; + break; + } + } + } + else if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest) { rest_index = i; - // ASTValidation verified there's only one Rest pattern break; } } @@ -375,7 +404,8 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern) auto rest_it = sub_patterns.begin () + *rest_index; items = std::make_unique<HIR::SlicePatternItemsHasRest> ( lower_pattern_seq (sub_patterns.begin (), rest_it), - lower_pattern_seq (rest_it + 1, sub_patterns.end ())); + lower_pattern_seq (rest_it + 1, sub_patterns.end ()), + std::move (rest_bind)); } else { @@ -383,7 +413,6 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern) lower_pattern_seq (sub_patterns.begin (), sub_patterns.end ())); } - auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index 29b3ff92a8b3..f21522b4d486 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -2375,6 +2375,8 @@ Dump::visit (SlicePatternItemsHasRest &e) { begin ("SlicePatternItemsHasRest"); visit_collection ("lower_patterns", e.get_lower_patterns ()); + if (e.has_rest_bind ()) + visit_field ("rest_bind", e.get_rest_bind ()); visit_collection ("upper_patterns", e.get_upper_patterns ()); end ("SlicePatternItemsHasRest"); } diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 90f8f57921a8..a56379d4a161 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -1437,16 +1437,22 @@ class SlicePatternItemsHasRest : public SlicePatternItems std::vector<std::unique_ptr<Pattern>> lower_patterns; std::vector<std::unique_ptr<Pattern>> upper_patterns; + // c in [a, b, c @ ..] + tl::optional<IdentifierPattern> rest_bind; + public: SlicePatternItemsHasRest ( std::vector<std::unique_ptr<Pattern>> lower_patterns, - std::vector<std::unique_ptr<Pattern>> upper_patterns) + std::vector<std::unique_ptr<Pattern>> upper_patterns, + tl::optional<IdentifierPattern> rest_bind) : lower_patterns (std::move (lower_patterns)), - upper_patterns (std::move (upper_patterns)) + upper_patterns (std::move (upper_patterns)), + rest_bind (std::move (rest_bind)) {} // Copy constructor with vector clone SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other) + : rest_bind (other.rest_bind) { lower_patterns.reserve (other.lower_patterns.size ()); for (const auto &e : other.lower_patterns) @@ -1470,6 +1476,8 @@ public: for (const auto &e : other.upper_patterns) upper_patterns.push_back (e->clone_pattern ()); + rest_bind = other.rest_bind; + return *this; } @@ -1502,6 +1510,20 @@ public: return upper_patterns; } + bool has_rest_bind () const { return rest_bind.has_value (); } + + IdentifierPattern &get_rest_bind () + { + rust_assert (has_rest_bind ()); + return *rest_bind; + } + + const IdentifierPattern &get_rest_bind () const + { + rust_assert (has_rest_bind ()); + return *rest_bind; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc b/gcc/rust/hir/tree/rust-hir-visitor.cc index 00b46e742f63..544c83db8b4d 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.cc +++ b/gcc/rust/hir/tree/rust-hir-visitor.cc @@ -1077,6 +1077,8 @@ DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items) { for (auto &lower : items.get_lower_patterns ()) lower->accept_vis (*this); + if (items.has_rest_bind ()) + items.get_rest_bind ().accept_vis (*this); for (auto &upper : items.get_upper_patterns ()) upper->accept_vis (*this); } diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 51b588a0218c..7d611ed5c76b 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2449,6 +2449,12 @@ SlicePatternItemsHasRest::to_string () const } } + str += "\n Rest binding pattern: "; + if (rest_bind) + str += rest_bind->to_string (); + else + str += "none"; + str += "\n Upper patterns: "; if (upper_patterns.empty ()) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 7d12bc7b4554..83104833dbea 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -942,6 +942,10 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) { auto &ref = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + + // TODO: support rest_bind (c in [a, b, c @ ..]) + rust_assert (!ref.has_rest_bind ()); + for (const auto &pattern_member : ref.get_lower_patterns ()) { TypeCheckPattern::Resolve (*pattern_member, parent_element_ty); diff --git a/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs new file mode 100644 index 000000000000..10316f750a76 --- /dev/null +++ b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-frust-compile-until=typecheck" } +#![feature(no_core)] +#![no_core] + +pub fn foo(x: &[u8]) -> i32 { + match x { + [] => 0, + [1, xs @ ..] => foo (xs), + [x, ..] => *x as i32 + } +}
