https://gcc.gnu.org/g:e919ef46c18e3e74d75bea1fa9cdf6fe44d20975
commit r16-4795-ge919ef46c18e3e74d75bea1fa9cdf6fe44d20975 Author: Yap Zhi Heng <[email protected]> Date: Mon Aug 11 21:51:11 2025 +0800 gccrs: Implement rest pattern support for slice patterns This patch adds support for compiling rest patterns present in slice patterns (e.g. `[1, .., 2]`). 006t.original output from compiling match-slicepattern-slice-2.rs for first 2 match arms: ... if (RUSTTMP.3.len > 1 && *NON_LVALUE_EXPR <RUSTTMP.3.data> == 1) { { struct () RUSTTMP.4; { struct () RUSTTMP.5; { .. } } goto <D.139>; } } if ((RUSTTMP.3.len > 1 && *NON_LVALUE_EXPR <RUSTTMP.3.data> == 0) && *(RUSTTMP.3.data + (sizetype) (RUSTTMP.3.len + 18446744073709551615) * 4) == 0) { { struct () RUSTTMP.6; { struct () RUSTTMP.7; { } } goto <D.139>; } } ... gcc/rust/ChangeLog: * hir/tree/rust-hir-pattern.h: Add SlicePatternItems base class and SlicePatternItemsNoRest/SlicePatternItemsHasRest derived classes. Update SlicePattern to hold patterns using the new classes. * hir/tree/rust-hir-full-decls.h: Declare new classes. * hir/tree/rust-hir.cc: Add visits for new classes. * hir/tree/rust-hir-visitor.h: Add visits for new classes. * hir/tree/rust-hir-visitor.cc: Implement visits for new classes. * hir/rust-hir-dump.h: Add visits for new classes. * hir/rust-hir-dump.cc: Implement Dump::visit for new classes. * hir/rust-ast-lower-base.h: Declare new lower_slice_pattern_no_rest/has_rest methods. * hir/rust-ast-lower-base.cc: Implement lower_slice_pattern_no_rest/has_rest to lower AST slice pattern items to HIR. * hir/rust-ast-lower-pattern.cc: Update ASTLoweringPattern::visit for SlicePattern to use new lowering methods. * backend/rust-compile-pattern.cc: Update CompilePatternCheckExpr::visit and CompilePatternBindings::visit for SlicePattern to handle SlicePatternItemsNoRest/HasRest. * checks/errors/borrowck/rust-bir-builder-pattern.cc: Update PatternBindingBuilder::visit for SlicePattern to iterate members correctly. * checks/errors/borrowck/rust-bir-builder-struct.h: Add visits for new classes. * checks/errors/borrowck/rust-function-collector.h: Add visits for new classes. * checks/errors/rust-const-checker.h: Add visits for new classes. * checks/errors/rust-const-checker.cc: Implement empty visits for new classes. * checks/errors/rust-hir-pattern-analysis.h: Add visits for new classes. * checks/errors/rust-hir-pattern-analysis.cc: Implement empty visits for new classes. * checks/errors/rust-unsafe-checker.h: Add visits for new classes. * checks/errors/rust-unsafe-checker.cc: Implement empty visits for new classes. * typecheck/rust-hir-type-check-pattern.cc: Update TypeCheckPattern::visit for SlicePattern to handle SlicePatternItemsNoRest/HasRest. gcc/testsuite/ChangeLog: * rust/compile/slice_rest_pattern.rs: Removed -fsyntax-only. Signed-off-by: Yap Zhi Heng <[email protected]> Diff: --- gcc/rust/backend/rust-compile-pattern.cc | 290 +++++++++++++++++---- .../errors/borrowck/rust-bir-builder-pattern.cc | 29 ++- .../errors/borrowck/rust-bir-builder-struct.h | 8 + .../errors/borrowck/rust-function-collector.h | 2 + gcc/rust/checks/errors/rust-const-checker.cc | 8 + gcc/rust/checks/errors/rust-const-checker.h | 2 + .../checks/errors/rust-hir-pattern-analysis.cc | 8 + gcc/rust/checks/errors/rust-hir-pattern-analysis.h | 2 + gcc/rust/checks/errors/rust-unsafe-checker.cc | 8 + gcc/rust/checks/errors/rust-unsafe-checker.h | 2 + gcc/rust/hir/rust-ast-lower-base.cc | 35 +++ gcc/rust/hir/rust-ast-lower-base.h | 6 + gcc/rust/hir/rust-ast-lower-pattern.cc | 13 +- gcc/rust/hir/rust-hir-dump.cc | 19 +- gcc/rust/hir/rust-hir-dump.h | 4 + gcc/rust/hir/tree/rust-hir-full-decls.h | 2 + gcc/rust/hir/tree/rust-hir-pattern.h | 179 +++++++++++-- gcc/rust/hir/tree/rust-hir-visitor.cc | 19 +- gcc/rust/hir/tree/rust-hir-visitor.h | 9 + gcc/rust/hir/tree/rust-hir.cc | 58 ++++- gcc/rust/typecheck/rust-hir-type-check-pattern.cc | 68 ++++- gcc/testsuite/rust/compile/slice_rest_pattern.rs | 3 +- .../execute/torture/match-slicepattern-array-2.rs | 27 ++ .../execute/torture/match-slicepattern-slice-2.rs | 28 ++ 24 files changed, 731 insertions(+), 98 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 577f8de9c93b..e29dc92ea49b 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -534,25 +534,14 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) || lookup->get_kind () == TyTy::TypeKind::SLICE || lookup->get_kind () == TyTy::REF); - size_t array_element_index = 0; + // function ptr that points to either array_index_expression or + // slice_index_expression depending on the scrutinee's type + tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr; + switch (lookup->get_kind ()) { case TyTy::TypeKind::ARRAY: - for (auto &pattern_member : pattern.get_items ()) - { - tree array_index_tree - = Backend::size_constant_expression (array_element_index++); - tree element_expr - = Backend::array_index_expression (match_scrutinee_expr, - array_index_tree, - pattern.get_locus ()); - tree check_expr_sub - = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, - ctx); - check_expr = Backend::arithmetic_or_logical_expression ( - ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, - check_expr_sub, pattern.get_locus ()); - } + scrutinee_index_expr_func = Backend::array_index_expression; break; case TyTy::TypeKind::SLICE: rust_sorry_at ( @@ -562,25 +551,81 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) case TyTy::TypeKind::REF: { rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr))); + scrutinee_index_expr_func = Backend::slice_index_expression; tree size_field = Backend::struct_field_expression (match_scrutinee_expr, 1, pattern.get_locus ()); - // First compare the size - check_expr = Backend::comparison_expression ( - ComparisonOperator::EQUAL, size_field, - build_int_cst (size_type_node, pattern.get_items ().size ()), - pattern.get_locus ()); + // for slices, generate a dynamic size comparison expression tree + // because size checking is done at runtime. + switch (pattern.get_items ().get_item_type ()) + { + case HIR::SlicePatternItems::ItemType::NO_REST: + { + auto &items = static_cast<HIR::SlicePatternItemsNoRest &> ( + pattern.get_items ()); + check_expr = Backend::comparison_expression ( + ComparisonOperator::EQUAL, size_field, + build_int_cst (size_type_node, items.get_patterns ().size ()), + pattern.get_locus ()); + } + break; + case HIR::SlicePatternItems::ItemType::HAS_REST: + { + auto &items = static_cast<HIR::SlicePatternItemsHasRest &> ( + pattern.get_items ()); + auto pattern_min_cap = items.get_lower_patterns ().size () + + items.get_upper_patterns ().size (); + check_expr = Backend::comparison_expression ( + ComparisonOperator::GREATER_OR_EQUAL, size_field, + build_int_cst (size_type_node, pattern_min_cap), + pattern.get_locus ()); + } + break; + } + } + break; + default: + rust_unreachable (); + } + + rust_assert (scrutinee_index_expr_func != nullptr); - // Then compare each element in the slice pattern - for (auto &pattern_member : pattern.get_items ()) + // Generate tree to compare every element within array/slice + size_t element_index = 0; + switch (pattern.get_items ().get_item_type ()) + { + case HIR::SlicePatternItems::ItemType::NO_REST: + { + auto &items + = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ()); + for (auto &pattern_member : items.get_patterns ()) { - tree slice_index_tree - = Backend::size_constant_expression (array_element_index++); + tree index_tree + = Backend::size_constant_expression (element_index++); tree element_expr - = Backend::slice_index_expression (match_scrutinee_expr, - slice_index_tree, - pattern.get_locus ()); + = scrutinee_index_expr_func (match_scrutinee_expr, index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + } + break; + } + case HIR::SlicePatternItems::ItemType::HAS_REST: + { + auto &items + = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + for (auto &pattern_member : items.get_lower_patterns ()) + { + tree index_tree + = Backend::size_constant_expression (element_index++); + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, index_tree, + pattern.get_locus ()); tree check_expr_sub = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, ctx); @@ -588,10 +633,71 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, check_expr_sub, pattern.get_locus ()); } + + // handle codegen for upper patterns differently for both types + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + { + // for array type scrutinee, we can simply get the capacity as a + // const and calculate how many elements to skip + auto array_ty = static_cast<TyTy::ArrayType *> (lookup); + auto cap_tree = array_ty->get_capacity ()->get_value (); + size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi (); + element_index = cap_wi - items.get_upper_patterns ().size (); + for (auto &pattern_member : items.get_upper_patterns ()) + { + tree index_tree + = Backend::size_constant_expression (element_index++); + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, + index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, + element_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + } + } + break; + case TyTy::TypeKind::REF: + { + // for slice type scrutinee, size is dyanamic, so number of + // elements to skip is calculated during runtime + tree slice_size + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern.get_locus ()); + tree upper_patterns_size = Backend::size_constant_expression ( + items.get_upper_patterns ().size ()); + tree index_tree = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::SUBTRACT, slice_size, + upper_patterns_size, pattern.get_locus ()); + for (auto &pattern_member : items.get_upper_patterns ()) + { + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, + index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, + element_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + index_tree = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::ADD, index_tree, + Backend::size_constant_expression (1), + pattern.get_locus ()); + } + } + break; + default: + rust_unreachable (); + } } break; - default: - rust_unreachable (); } } @@ -932,43 +1038,121 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern) || lookup->get_kind () == TyTy::TypeKind::SLICE || lookup->get_kind () == TyTy::REF); - size_t array_element_index = 0; + // function ptr that points to either array_index_expression or + // slice_index_expression depending on the scrutinee's type + tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr; + switch (lookup->get_kind ()) { case TyTy::TypeKind::ARRAY: - for (auto &pattern_member : pattern.get_items ()) - { - tree array_index_tree - = Backend::size_constant_expression (array_element_index++); - tree element_expr - = Backend::array_index_expression (match_scrutinee_expr, - array_index_tree, - pattern.get_locus ()); - CompilePatternBindings::Compile (*pattern_member, element_expr, ctx); - } + scrutinee_index_expr_func = Backend::array_index_expression; break; case TyTy::TypeKind::SLICE: - rust_sorry_at ( - pattern.get_locus (), - "SlicePattern matching against non-ref slices are not yet supported"); + rust_sorry_at (pattern.get_locus (), + "SlicePattern matching against non-ref slices are " + "not yet supported"); break; case TyTy::TypeKind::REF: + scrutinee_index_expr_func = Backend::slice_index_expression; + break; + default: + rust_unreachable (); + } + + rust_assert (scrutinee_index_expr_func != nullptr); + + size_t element_index = 0; + + switch (pattern.get_items ().get_item_type ()) + { + case HIR::SlicePatternItems::ItemType::NO_REST: { - for (auto &pattern_member : pattern.get_items ()) + auto &items + = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ()); + for (auto &pattern_member : items.get_patterns ()) { - tree slice_index_tree - = Backend::size_constant_expression (array_element_index++); + tree index_tree + = Backend::size_constant_expression (element_index++); tree element_expr - = Backend::slice_index_expression (match_scrutinee_expr, - slice_index_tree, - pattern.get_locus ()); + = scrutinee_index_expr_func (match_scrutinee_expr, index_tree, + pattern.get_locus ()); CompilePatternBindings::Compile (*pattern_member, element_expr, ctx); } - break; } - default: - rust_unreachable (); + break; + case HIR::SlicePatternItems::ItemType::HAS_REST: + { + auto &items + = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + for (auto &pattern_member : items.get_lower_patterns ()) + { + tree index_tree + = Backend::size_constant_expression (element_index++); + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, element_expr, + ctx); + } + + // handle codegen for upper patterns differently for both types + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + { + auto array_ty = static_cast<TyTy::ArrayType *> (lookup); + auto cap_tree = array_ty->get_capacity ()->get_value (); + size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi (); + element_index = cap_wi - items.get_upper_patterns ().size (); + for (auto &pattern_member : items.get_upper_patterns ()) + { + tree index_tree + = Backend::size_constant_expression (element_index++); + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, + index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, + element_expr, ctx); + } + } + break; + case TyTy::TypeKind::SLICE: + rust_sorry_at (pattern.get_locus (), + "SlicePattern matching against non-ref slices are " + "not yet supported"); + break; + case TyTy::TypeKind::REF: + { + tree slice_size + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern.get_locus ()); + tree upper_patterns_size = Backend::size_constant_expression ( + items.get_upper_patterns ().size ()); + tree index_tree = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::SUBTRACT, slice_size, + upper_patterns_size, pattern.get_locus ()); + for (auto &pattern_member : items.get_upper_patterns ()) + { + tree element_expr + = scrutinee_index_expr_func (match_scrutinee_expr, + index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, + element_expr, ctx); + index_tree = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::ADD, index_tree, + Backend::size_constant_expression (1), + pattern.get_locus ()); + } + } + break; + default: + rust_unreachable (); + } + } + break; } } 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 18f9584a4f0e..e78d7505094b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -70,11 +70,34 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern) return ty->as<TyTy::SliceType> ()->get_element_type (); }); - // Regions are unchnaged. + // Regions are unchanged. - for (auto &item : pattern.get_items ()) + switch (pattern.get_items ().get_item_type ()) { - item->accept_vis (*this); + case HIR::SlicePatternItems::NO_REST: + { + auto &items + = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ()); + for (auto &member : items.get_patterns ()) + { + member->accept_vis (*this); + } + break; + } + case HIR::SlicePatternItems::HAS_REST: + { + auto &items + = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + for (auto &member : items.get_lower_patterns ()) + { + member->accept_vis (*this); + } + for (auto &member : items.get_upper_patterns ()) + { + member->accept_vis (*this); + } + break; + } } } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index f05dd6ceb1ba..6cb87c7568ac 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -246,6 +246,14 @@ protected: rust_unreachable (); } void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); } + void visit (HIR::SlicePatternItemsNoRest &tuple_items) override + { + rust_unreachable (); + } + void visit (HIR::SlicePatternItemsHasRest &tuple_items) override + { + rust_unreachable (); + } void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); } void visit (HIR::AltPattern &pattern) override { rust_unreachable (); } void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); } diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index f4a11702a854..63f2a95f4bfd 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -176,6 +176,8 @@ public: void visit (HIR::TuplePatternItemsNoRest &tuple_items) override {} void visit (HIR::TuplePatternItemsHasRest &tuple_items) override {} void visit (HIR::TuplePattern &pattern) override {} + void visit (HIR::SlicePatternItemsNoRest &tuple_items) override {} + void visit (HIR::SlicePatternItemsHasRest &tuple_items) override {} void visit (HIR::SlicePattern &pattern) override {} void visit (HIR::AltPattern &pattern) override {} void visit (HIR::EmptyStmt &stmt) override {} diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 845e5b68187f..782d6940bbee 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -836,6 +836,14 @@ void ConstChecker::visit (TuplePattern &) {} +void +ConstChecker::visit (SlicePatternItemsNoRest &) +{} + +void +ConstChecker::visit (SlicePatternItemsHasRest &) +{} + void ConstChecker::visit (SlicePattern &) {} diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 66138bdc851a..d464b7b9fce5 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -186,6 +186,8 @@ private: virtual void visit (TuplePatternItemsNoRest &tuple_items) override; virtual void visit (TuplePatternItemsHasRest &tuple_items) override; virtual void visit (TuplePattern &pattern) override; + virtual void visit (SlicePatternItemsNoRest &items) override; + virtual void visit (SlicePatternItemsHasRest &items) override; virtual void visit (SlicePattern &pattern) override; virtual void visit (AltPattern &pattern) override; virtual void visit (EmptyStmt &stmt) override; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index 7fe7f029f2aa..290087c573f1 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -663,6 +663,14 @@ void PatternChecker::visit (TuplePattern &) {} +void +PatternChecker::visit (SlicePatternItemsNoRest &) +{} + +void +PatternChecker::visit (SlicePatternItemsHasRest &) +{} + void PatternChecker::visit (SlicePattern &) {} diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 6aefaeca63fc..d75e900f2be4 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -159,6 +159,8 @@ private: virtual void visit (TuplePatternItemsNoRest &tuple_items) override; virtual void visit (TuplePatternItemsHasRest &tuple_items) override; virtual void visit (TuplePattern &pattern) override; + virtual void visit (SlicePatternItemsNoRest &items) override; + virtual void visit (SlicePatternItemsHasRest &items) override; virtual void visit (SlicePattern &pattern) override; virtual void visit (AltPattern &pattern) override; virtual void visit (EmptyStmt &stmt) override; diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 41ed698db778..607d20fa11f7 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -949,6 +949,14 @@ void UnsafeChecker::visit (TuplePattern &) {} +void +UnsafeChecker::visit (SlicePatternItemsNoRest &) +{} + +void +UnsafeChecker::visit (SlicePatternItemsHasRest &) +{} + void UnsafeChecker::visit (SlicePattern &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 4c884ad6b047..420668f46ed8 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -167,6 +167,8 @@ private: virtual void visit (TuplePatternItemsNoRest &tuple_items) override; virtual void visit (TuplePatternItemsHasRest &tuple_items) override; virtual void visit (TuplePattern &pattern) override; + virtual void visit (SlicePatternItemsNoRest &items) override; + virtual void visit (SlicePatternItemsHasRest &items) override; virtual void visit (SlicePattern &pattern) override; virtual void visit (AltPattern &pattern) override; virtual void visit (EmptyStmt &stmt) override; diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index f3ae3ce71a3d..e32918e8e85b 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -906,6 +906,41 @@ ASTLoweringBase::lower_tuple_pattern_ranged ( std::move (upper_patterns))); } +std::unique_ptr<HIR::SlicePatternItems> +ASTLoweringBase::lower_slice_pattern_no_rest ( + AST::SlicePatternItemsNoRest &pattern) +{ + std::vector<std::unique_ptr<HIR::Pattern>> patterns; + patterns.reserve (pattern.get_patterns ().size ()); + for (auto &p : pattern.get_patterns ()) + patterns.emplace_back (ASTLoweringPattern::translate (*p)); + + return std::unique_ptr<HIR::SlicePatternItems> ( + new HIR::SlicePatternItemsNoRest (std::move (patterns))); +} + +std::unique_ptr<HIR::SlicePatternItems> +ASTLoweringBase::lower_slice_pattern_has_rest ( + AST::SlicePatternItemsHasRest &pattern) +{ + std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns; + lower_patterns.reserve (pattern.get_lower_patterns ().size ()); + std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns; + upper_patterns.reserve (pattern.get_upper_patterns ().size ()); + + for (auto &p : pattern.get_lower_patterns ()) + lower_patterns.emplace_back ( + std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p))); + + for (auto &p : pattern.get_upper_patterns ()) + upper_patterns.emplace_back ( + std::unique_ptr<HIR::Pattern> (ASTLoweringPattern::translate (*p))); + + return std::unique_ptr<HIR::SlicePatternItems> ( + new HIR::SlicePatternItemsHasRest (std::move (lower_patterns), + std::move (upper_patterns))); +} + std::unique_ptr<HIR::RangePatternBound> ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) { diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index e86aacb216a6..a188e1785268 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -322,6 +322,12 @@ protected: std::unique_ptr<TuplePatternItems> lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern); + std::unique_ptr<SlicePatternItems> + lower_slice_pattern_no_rest (AST::SlicePatternItemsNoRest &pattern); + + std::unique_ptr<SlicePatternItems> + lower_slice_pattern_has_rest (AST::SlicePatternItemsHasRest &pattern); + std::unique_ptr<HIR::RangePatternBound> lower_range_pattern_bound (AST::RangePatternBound &bound); diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index f1b3ba8cfad9..6933c2dca834 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -322,23 +322,22 @@ ASTLoweringPattern::visit (AST::ReferencePattern &pattern) void ASTLoweringPattern::visit (AST::SlicePattern &pattern) { - std::vector<std::unique_ptr<HIR::Pattern>> items; + std::unique_ptr<HIR::SlicePatternItems> items; switch (pattern.get_items ().get_pattern_type ()) { case AST::SlicePatternItems::SlicePatternItemType::NO_REST: { - AST::SlicePatternItemsNoRest &ref + auto &ref = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ()); - for (auto &p : ref.get_patterns ()) - items.emplace_back (ASTLoweringPattern::translate (*p)); + items = ASTLoweringBase::lower_slice_pattern_no_rest (ref); } break; case AST::SlicePatternItems::SlicePatternItemType::HAS_REST: { - rust_error_at (pattern.get_locus (), - "lowering of slice patterns with rest elements are not " - "supported yet"); + auto &ref + = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ()); + items = ASTLoweringBase::lower_slice_pattern_has_rest (ref); } break; } diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index b5c2bcf24fec..49ce14378999 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -2362,12 +2362,29 @@ Dump::visit (TuplePattern &e) end ("TuplePattern"); } +void +Dump::visit (SlicePatternItemsNoRest &e) +{ + begin ("SlicePatternItemsNoRest"); + visit_collection ("patterns", e.get_patterns ()); + end ("SlicePatternItemsNoRest"); +} + +void +Dump::visit (SlicePatternItemsHasRest &e) +{ + begin ("SlicePatternItemsHasRest"); + visit_collection ("lower_patterns", e.get_lower_patterns ()); + visit_collection ("upper_patterns", e.get_upper_patterns ()); + end ("SlicePatternItemsHasRest"); +} + void Dump::visit (SlicePattern &e) { begin ("SlicePattern"); do_mappings (e.get_mappings ()); - visit_collection ("items", e.get_items ()); + visit_field ("items", e.get_items ()); end ("SlicePattern"); } diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index 0202210db873..4dfc8859393f 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -230,7 +230,11 @@ private: virtual void visit (TuplePatternItemsNoRest &) override; virtual void visit (TuplePatternItemsHasRest &) override; virtual void visit (TuplePattern &) override; + + virtual void visit (SlicePatternItemsNoRest &) override; + virtual void visit (SlicePatternItemsHasRest &) override; virtual void visit (SlicePattern &) override; + virtual void visit (AltPattern &) override; virtual void visit (EmptyStmt &) override; diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index b52ccb402860..aec2f362e44e 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -206,6 +206,8 @@ class TuplePatternItems; class TuplePatternItemsNoRest; class TuplePatternItemsHasRest; class TuplePattern; +class SlicePatternItemsNoRest; +class SlicePatternItemsHasRest; class SlicePattern; class AltPattern; diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 2a2965875f89..e3581dc5c8c8 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -1241,10 +1241,161 @@ protected: } }; +// Base abstract class representing SlicePattern patterns +class SlicePatternItems : public PatternItems +{ +public: + // Unique pointer custom clone function + std::unique_ptr<SlicePatternItems> clone_slice_pattern_items () const + { + return std::unique_ptr<SlicePatternItems> (clone_pattern_items_impl ()); + } + +protected: + // pure virtual clone implementation + virtual SlicePatternItems *clone_pattern_items_impl () const override = 0; +}; + +// Class representing patterns within a SlicePattern, without a rest pattern +class SlicePatternItemsNoRest : public SlicePatternItems +{ + std::vector<std::unique_ptr<Pattern>> patterns; + +public: + SlicePatternItemsNoRest (std::vector<std::unique_ptr<Pattern>> patterns) + : patterns (std::move (patterns)) + {} + + // Copy constructor with vector clone + SlicePatternItemsNoRest (SlicePatternItemsNoRest const &other) + { + patterns.reserve (other.patterns.size ()); + for (const auto &e : other.patterns) + patterns.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to vector clone + SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest const &other) + { + patterns.clear (); + patterns.reserve (other.patterns.size ()); + for (const auto &e : other.patterns) + patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + SlicePatternItemsNoRest (SlicePatternItemsNoRest &&other) = default; + SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest &&other) + = default; + + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + + ItemType get_item_type () const override { return ItemType::NO_REST; } + + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const + { + return patterns; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + SlicePatternItemsNoRest *clone_pattern_items_impl () const override + { + return new SlicePatternItemsNoRest (*this); + } +}; + +// Class representing patterns within a SlicePattern, with a rest pattern +// included +class SlicePatternItemsHasRest : public SlicePatternItems +{ + std::vector<std::unique_ptr<Pattern>> lower_patterns; + std::vector<std::unique_ptr<Pattern>> upper_patterns; + +public: + SlicePatternItemsHasRest ( + std::vector<std::unique_ptr<Pattern>> lower_patterns, + std::vector<std::unique_ptr<Pattern>> upper_patterns) + : lower_patterns (std::move (lower_patterns)), + upper_patterns (std::move (upper_patterns)) + {} + + // Copy constructor with vector clone + SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other) + { + lower_patterns.reserve (other.lower_patterns.size ()); + for (const auto &e : other.lower_patterns) + lower_patterns.push_back (e->clone_pattern ()); + + upper_patterns.reserve (other.upper_patterns.size ()); + for (const auto &e : other.upper_patterns) + upper_patterns.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to clone + SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest const &other) + { + lower_patterns.clear (); + lower_patterns.reserve (other.lower_patterns.size ()); + for (const auto &e : other.lower_patterns) + lower_patterns.push_back (e->clone_pattern ()); + + lower_patterns.clear (); + upper_patterns.reserve (other.upper_patterns.size ()); + for (const auto &e : other.upper_patterns) + upper_patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + SlicePatternItemsHasRest (SlicePatternItemsHasRest &&other) = default; + SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest &&other) + = default; + + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + + ItemType get_item_type () const override { return ItemType::HAS_REST; } + + std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () + { + return lower_patterns; + } + const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const + { + return lower_patterns; + } + + std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () + { + return upper_patterns; + } + const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const + { + return upper_patterns; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + SlicePatternItemsHasRest *clone_pattern_items_impl () const override + { + return new SlicePatternItemsHasRest (*this); + } +}; + // HIR node representing patterns that can match slices and arrays class SlicePattern : public Pattern { - std::vector<std::unique_ptr<Pattern>> items; + std::unique_ptr<SlicePatternItems> items; location_t locus; Analysis::NodeMapping mappings; @@ -1252,30 +1403,23 @@ public: std::string as_string () const override; SlicePattern (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Pattern>> items, location_t locus) + std::unique_ptr<SlicePatternItems> items, location_t locus) : items (std::move (items)), locus (locus), mappings (mappings) {} - // Copy constructor with vector clone + // Copy constructor requires clone SlicePattern (SlicePattern const &other) - : locus (other.locus), mappings (other.mappings) - { - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_pattern ()); - } + : items (other.items->clone_slice_pattern_items ()), locus (other.locus), + mappings (other.mappings) + {} // Overloaded assignment operator to vector clone SlicePattern &operator= (SlicePattern const &other) { + items = other.items->clone_slice_pattern_items (); locus = other.locus; mappings = other.mappings; - items.clear (); - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_pattern ()); - return *this; } @@ -1283,11 +1427,8 @@ public: SlicePattern (SlicePattern &&other) = default; SlicePattern &operator= (SlicePattern &&other) = default; - std::vector<std::unique_ptr<Pattern>> &get_items () { return items; } - const std::vector<std::unique_ptr<Pattern>> &get_items () const - { - return items; - } + SlicePatternItems &get_items () { return *items; } + const SlicePatternItems &get_items () const { return *items; } location_t get_locus () const override { return locus; } diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc b/gcc/rust/hir/tree/rust-hir-visitor.cc index 15db3f0d6dfe..1e201a5541e4 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.cc +++ b/gcc/rust/hir/tree/rust-hir-visitor.cc @@ -1067,11 +1067,26 @@ DefaultHIRVisitor::walk (TuplePattern &pattern) pattern.get_items ().accept_vis (*this); } +void +DefaultHIRVisitor::walk (SlicePatternItemsNoRest &items) +{ + for (auto &pattern : items.get_patterns ()) + pattern->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items) +{ + for (auto &lower : items.get_lower_patterns ()) + lower->accept_vis (*this); + for (auto &upper : items.get_upper_patterns ()) + upper->accept_vis (*this); +} + void DefaultHIRVisitor::walk (SlicePattern &pattern) { - for (auto &item : pattern.get_items ()) - item->accept_vis (*this); + pattern.get_items ().accept_vis (*this); } void diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index d0bb484b41ee..77760b0141dc 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -138,6 +138,8 @@ public: virtual void visit (TuplePatternItemsNoRest &tuple_items) = 0; virtual void visit (TuplePatternItemsHasRest &tuple_items) = 0; virtual void visit (TuplePattern &pattern) = 0; + virtual void visit (SlicePatternItemsNoRest &items) = 0; + virtual void visit (SlicePatternItemsHasRest &items) = 0; virtual void visit (SlicePattern &pattern) = 0; virtual void visit (AltPattern &pattern) = 0; virtual void visit (EmptyStmt &stmt) = 0; @@ -311,6 +313,8 @@ public: virtual void visit (TuplePatternItemsNoRest &node) override { walk (node); } virtual void visit (TuplePatternItemsHasRest &node) override { walk (node); } virtual void visit (TuplePattern &node) override { walk (node); } + virtual void visit (SlicePatternItemsNoRest &node) override { walk (node); } + virtual void visit (SlicePatternItemsHasRest &node) override { walk (node); } virtual void visit (SlicePattern &node) override { walk (node); } virtual void visit (AltPattern &node) override { walk (node); } virtual void visit (EmptyStmt &node) override { walk (node); } @@ -444,6 +448,8 @@ protected: virtual void walk (TuplePatternItemsNoRest &) final; virtual void walk (TuplePatternItemsHasRest &) final; virtual void walk (TuplePattern &) final; + virtual void walk (SlicePatternItemsNoRest &) final; + virtual void walk (SlicePatternItemsHasRest &) final; virtual void walk (SlicePattern &) final; virtual void walk (AltPattern &) final; virtual void walk (EmptyStmt &) final; @@ -593,6 +599,9 @@ public: virtual void visit (TuplePatternItemsNoRest &) override {} virtual void visit (TuplePatternItemsHasRest &) override {} virtual void visit (TuplePattern &) override {} + + virtual void visit (SlicePatternItemsNoRest &) override {} + virtual void visit (SlicePatternItemsHasRest &) override {} virtual void visit (SlicePattern &) override {} virtual void visit (AltPattern &) override {} diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 39c0e2e1c292..7aad4ef27303 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2386,11 +2386,11 @@ RangePatternBoundLiteral::as_string () const } std::string -SlicePattern::as_string () const +SlicePatternItemsNoRest::as_string () const { - std::string str ("SlicePattern: "); + std::string str; - for (const auto &pattern : items) + for (const auto &pattern : patterns) { str += "\n " + pattern->as_string (); } @@ -2398,6 +2398,46 @@ SlicePattern::as_string () const return str; } +std::string +SlicePatternItemsHasRest::as_string () const +{ + std::string str; + + str += "\n Lower patterns: "; + if (lower_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &lower : lower_patterns) + { + str += "\n " + lower->as_string (); + } + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &upper : upper_patterns) + { + str += "\n " + upper->as_string (); + } + } + + return str; +} + +std::string +SlicePattern::as_string () const +{ + return "SlicePattern: " + items->as_string (); +} + std::string AltPattern::as_string () const { @@ -4505,6 +4545,18 @@ TuplePattern::accept_vis (HIRFullVisitor &vis) vis.visit (*this); } +void +SlicePatternItemsNoRest::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + +void +SlicePatternItemsHasRest::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + void SlicePattern::accept_vis (HIRFullVisitor &vis) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index b34679eb6b40..5a2dde85e18a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -651,14 +651,44 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) break; } auto cap_wi = wi::to_wide (cap).to_uhwi (); - if (cap_wi != pattern.get_items ().size ()) + + // size check during compile time + switch (pattern.get_items ().get_item_type ()) { - rust_error_at (pattern.get_locus (), ErrorCode::E0527, - "pattern requires %lu elements but array has %lu", - (unsigned long) pattern.get_items ().size (), - (unsigned long) cap_wi); + case HIR::SlicePatternItems::ItemType::NO_REST: + { + auto &ref = static_cast<HIR::SlicePatternItemsNoRest &> ( + pattern.get_items ()); + if (cap_wi != ref.get_patterns ().size ()) + { + rust_error_at ( + pattern.get_locus (), ErrorCode::E0527, + "pattern requires %lu elements but array has %lu", + (unsigned long) ref.get_patterns ().size (), + (unsigned long) cap_wi); + break; + } + } + break; + case HIR::SlicePatternItems::ItemType::HAS_REST: + { + auto &ref = static_cast<HIR::SlicePatternItemsHasRest &> ( + pattern.get_items ()); + auto pattern_min_cap = ref.get_lower_patterns ().size () + + ref.get_upper_patterns ().size (); + + if (cap_wi < pattern_min_cap) + { + rust_error_at ( + pattern.get_locus (), ErrorCode::E0528, + "pattern requires at least %lu elements but array has %lu", + (unsigned long) pattern_min_cap, (unsigned long) cap_wi); + break; + } + } break; } + break; } case TyTy::SLICE: @@ -694,10 +724,32 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) infered->set_ref (pattern.get_mappings ().get_hirid ()); // Type check every item in the SlicePattern against parent's element ty - // TODO update this after adding support for RestPattern in SlicePattern - for (const auto &item : pattern.get_items ()) + switch (pattern.get_items ().get_item_type ()) { - TypeCheckPattern::Resolve (*item, parent_element_ty); + case HIR::SlicePatternItems::ItemType::NO_REST: + { + auto &ref + = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ()); + for (const auto &pattern_member : ref.get_patterns ()) + { + TypeCheckPattern::Resolve (*pattern_member, parent_element_ty); + } + break; + } + case HIR::SlicePatternItems::ItemType::HAS_REST: + { + auto &ref + = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ()); + for (const auto &pattern_member : ref.get_lower_patterns ()) + { + TypeCheckPattern::Resolve (*pattern_member, parent_element_ty); + } + for (const auto &pattern_member : ref.get_upper_patterns ()) + { + TypeCheckPattern::Resolve (*pattern_member, parent_element_ty); + } + break; + } } } diff --git a/gcc/testsuite/rust/compile/slice_rest_pattern.rs b/gcc/testsuite/rust/compile/slice_rest_pattern.rs index c27a8dd777e4..bb3c414173a3 100644 --- a/gcc/testsuite/rust/compile/slice_rest_pattern.rs +++ b/gcc/testsuite/rust/compile/slice_rest_pattern.rs @@ -1,5 +1,4 @@ -// { dg-options "-fsyntax-only" } -fn foo(a: &[u32]) { +pub fn foo(a: &[u32]) { match a { [first, ..] => {} [.., last] => {} diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs new file mode 100644 index 000000000000..c6e77627b4d2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs @@ -0,0 +1,27 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let a = [0, 4, 5, 6, 1]; + let mut ret = 1; + + match a { + [1, .., b] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + } + [0, .., 0] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + [0, .., b] => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs new file mode 100644 index 000000000000..2fdffbb29f9d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs @@ -0,0 +1,28 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let arr = [0, 4, 5, 6, 1]; + let a: &[i32] = &arr; + let mut ret = 1; + + match a { + [1, .., b] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + } + [0, .., 0] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + [0, .., b] => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +}
