Skip to content

Commit feed751

Browse files
committed
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 slice_rest_pattern.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]>
1 parent 5b7a0d7 commit feed751

24 files changed

+731
-97
lines changed

gcc/rust/backend/rust-compile-pattern.cc

Lines changed: 237 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -534,25 +534,14 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
534534
|| lookup->get_kind () == TyTy::TypeKind::SLICE
535535
|| lookup->get_kind () == TyTy::REF);
536536

537-
size_t array_element_index = 0;
537+
// function ptr that points to either array_index_expression or
538+
// slice_index_expression depending on the scrutinee's type
539+
tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
540+
538541
switch (lookup->get_kind ())
539542
{
540543
case TyTy::TypeKind::ARRAY:
541-
for (auto &pattern_member : pattern.get_items ())
542-
{
543-
tree array_index_tree
544-
= Backend::size_constant_expression (array_element_index++);
545-
tree element_expr
546-
= Backend::array_index_expression (match_scrutinee_expr,
547-
array_index_tree,
548-
pattern.get_locus ());
549-
tree check_expr_sub
550-
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
551-
ctx);
552-
check_expr = Backend::arithmetic_or_logical_expression (
553-
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
554-
check_expr_sub, pattern.get_locus ());
555-
}
544+
scrutinee_index_expr_func = Backend::array_index_expression;
556545
break;
557546
case TyTy::TypeKind::SLICE:
558547
rust_sorry_at (
@@ -562,36 +551,153 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
562551
case TyTy::TypeKind::REF:
563552
{
564553
rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
554+
scrutinee_index_expr_func = Backend::slice_index_expression;
565555
tree size_field
566556
= Backend::struct_field_expression (match_scrutinee_expr, 1,
567557
pattern.get_locus ());
568558

569-
// First compare the size
570-
check_expr = Backend::comparison_expression (
571-
ComparisonOperator::EQUAL, size_field,
572-
build_int_cst (size_type_node, pattern.get_items ().size ()),
573-
pattern.get_locus ());
559+
// for slices, generate a dynamic size comparison expression tree
560+
// because size checking is done at runtime.
561+
switch (pattern.get_items ().get_item_type ())
562+
{
563+
case HIR::SlicePatternItems::ItemType::NO_REST:
564+
{
565+
auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
566+
pattern.get_items ());
567+
check_expr = Backend::comparison_expression (
568+
ComparisonOperator::EQUAL, size_field,
569+
build_int_cst (size_type_node, items.get_patterns ().size ()),
570+
pattern.get_locus ());
571+
}
572+
break;
573+
case HIR::SlicePatternItems::ItemType::HAS_REST:
574+
{
575+
auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
576+
pattern.get_items ());
577+
auto pattern_min_cap = items.get_lower_patterns ().size ()
578+
+ items.get_upper_patterns ().size ();
579+
check_expr = Backend::comparison_expression (
580+
ComparisonOperator::GREATER_OR_EQUAL, size_field,
581+
build_int_cst (size_type_node, pattern_min_cap),
582+
pattern.get_locus ());
583+
}
584+
break;
585+
}
586+
}
587+
break;
588+
default:
589+
rust_unreachable ();
590+
}
591+
592+
rust_assert (scrutinee_index_expr_func != nullptr);
574593

575-
// Then compare each element in the slice pattern
576-
for (auto &pattern_member : pattern.get_items ())
594+
// Generate tree to compare every element within array/slice
595+
size_t element_index = 0;
596+
switch (pattern.get_items ().get_item_type ())
597+
{
598+
case HIR::SlicePatternItems::ItemType::NO_REST:
599+
{
600+
auto &items
601+
= static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
602+
for (auto &pattern_member : items.get_patterns ())
577603
{
578-
tree slice_index_tree
579-
= Backend::size_constant_expression (array_element_index++);
604+
tree index_tree
605+
= Backend::size_constant_expression (element_index++);
580606
tree element_expr
581-
= Backend::slice_index_expression (match_scrutinee_expr,
582-
slice_index_tree,
583-
pattern.get_locus ());
607+
= scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
608+
pattern.get_locus ());
609+
tree check_expr_sub
610+
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
611+
ctx);
612+
check_expr = Backend::arithmetic_or_logical_expression (
613+
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
614+
check_expr_sub, pattern.get_locus ());
615+
}
616+
break;
617+
}
618+
case HIR::SlicePatternItems::ItemType::HAS_REST:
619+
{
620+
auto &items
621+
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
622+
for (auto &pattern_member : items.get_lower_patterns ())
623+
{
624+
tree index_tree
625+
= Backend::size_constant_expression (element_index++);
626+
tree element_expr
627+
= scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
628+
pattern.get_locus ());
584629
tree check_expr_sub
585630
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
586631
ctx);
587632
check_expr = Backend::arithmetic_or_logical_expression (
588633
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
589634
check_expr_sub, pattern.get_locus ());
590635
}
636+
637+
// handle codegen for upper patterns differently for both types
638+
switch (lookup->get_kind ())
639+
{
640+
case TyTy::TypeKind::ARRAY:
641+
{
642+
// for array type scrutinee, we can simply get the capacity as a
643+
// const and calculate how many elements to skip
644+
auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
645+
auto cap_tree = array_ty->get_capacity ()->get_value ();
646+
size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
647+
element_index = cap_wi - items.get_upper_patterns ().size ();
648+
for (auto &pattern_member : items.get_upper_patterns ())
649+
{
650+
tree index_tree
651+
= Backend::size_constant_expression (element_index++);
652+
tree element_expr
653+
= scrutinee_index_expr_func (match_scrutinee_expr,
654+
index_tree,
655+
pattern.get_locus ());
656+
tree check_expr_sub
657+
= CompilePatternCheckExpr::Compile (*pattern_member,
658+
element_expr, ctx);
659+
check_expr = Backend::arithmetic_or_logical_expression (
660+
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
661+
check_expr_sub, pattern.get_locus ());
662+
}
663+
}
664+
break;
665+
case TyTy::TypeKind::REF:
666+
{
667+
// for slice type scrutinee, size is dyanamic, so number of
668+
// elements to skip is calculated during runtime
669+
tree slice_size
670+
= Backend::struct_field_expression (match_scrutinee_expr, 1,
671+
pattern.get_locus ());
672+
tree upper_patterns_size = Backend::size_constant_expression (
673+
items.get_upper_patterns ().size ());
674+
tree index_tree = Backend::arithmetic_or_logical_expression (
675+
ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
676+
upper_patterns_size, pattern.get_locus ());
677+
for (auto &pattern_member : items.get_upper_patterns ())
678+
{
679+
tree element_expr
680+
= scrutinee_index_expr_func (match_scrutinee_expr,
681+
index_tree,
682+
pattern.get_locus ());
683+
tree check_expr_sub
684+
= CompilePatternCheckExpr::Compile (*pattern_member,
685+
element_expr, ctx);
686+
check_expr = Backend::arithmetic_or_logical_expression (
687+
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
688+
check_expr_sub, pattern.get_locus ());
689+
index_tree = Backend::arithmetic_or_logical_expression (
690+
ArithmeticOrLogicalOperator::ADD, index_tree,
691+
Backend::size_constant_expression (1),
692+
pattern.get_locus ());
693+
}
694+
}
695+
break;
696+
default:
697+
rust_unreachable ();
698+
}
591699
}
592700
break;
593-
default:
594-
rust_unreachable ();
595701
}
596702
}
597703

@@ -932,43 +1038,121 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern)
9321038
|| lookup->get_kind () == TyTy::TypeKind::SLICE
9331039
|| lookup->get_kind () == TyTy::REF);
9341040

935-
size_t array_element_index = 0;
1041+
// function ptr that points to either array_index_expression or
1042+
// slice_index_expression depending on the scrutinee's type
1043+
tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
1044+
9361045
switch (lookup->get_kind ())
9371046
{
9381047
case TyTy::TypeKind::ARRAY:
939-
for (auto &pattern_member : pattern.get_items ())
940-
{
941-
tree array_index_tree
942-
= Backend::size_constant_expression (array_element_index++);
943-
tree element_expr
944-
= Backend::array_index_expression (match_scrutinee_expr,
945-
array_index_tree,
946-
pattern.get_locus ());
947-
CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
948-
}
1048+
scrutinee_index_expr_func = Backend::array_index_expression;
9491049
break;
9501050
case TyTy::TypeKind::SLICE:
951-
rust_sorry_at (
952-
pattern.get_locus (),
953-
"SlicePattern matching against non-ref slices are not yet supported");
1051+
rust_sorry_at (pattern.get_locus (),
1052+
"SlicePattern matching against non-ref slices are "
1053+
"not yet supported");
9541054
break;
9551055
case TyTy::TypeKind::REF:
1056+
scrutinee_index_expr_func = Backend::slice_index_expression;
1057+
break;
1058+
default:
1059+
rust_unreachable ();
1060+
}
1061+
1062+
rust_assert (scrutinee_index_expr_func != nullptr);
1063+
1064+
size_t element_index = 0;
1065+
1066+
switch (pattern.get_items ().get_item_type ())
1067+
{
1068+
case HIR::SlicePatternItems::ItemType::NO_REST:
9561069
{
957-
for (auto &pattern_member : pattern.get_items ())
1070+
auto &items
1071+
= static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
1072+
for (auto &pattern_member : items.get_patterns ())
9581073
{
959-
tree slice_index_tree
960-
= Backend::size_constant_expression (array_element_index++);
1074+
tree index_tree
1075+
= Backend::size_constant_expression (element_index++);
9611076
tree element_expr
962-
= Backend::slice_index_expression (match_scrutinee_expr,
963-
slice_index_tree,
964-
pattern.get_locus ());
1077+
= scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1078+
pattern.get_locus ());
9651079
CompilePatternBindings::Compile (*pattern_member, element_expr,
9661080
ctx);
9671081
}
968-
break;
9691082
}
970-
default:
971-
rust_unreachable ();
1083+
break;
1084+
case HIR::SlicePatternItems::ItemType::HAS_REST:
1085+
{
1086+
auto &items
1087+
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
1088+
for (auto &pattern_member : items.get_lower_patterns ())
1089+
{
1090+
tree index_tree
1091+
= Backend::size_constant_expression (element_index++);
1092+
tree element_expr
1093+
= scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1094+
pattern.get_locus ());
1095+
CompilePatternBindings::Compile (*pattern_member, element_expr,
1096+
ctx);
1097+
}
1098+
1099+
// handle codegen for upper patterns differently for both types
1100+
switch (lookup->get_kind ())
1101+
{
1102+
case TyTy::TypeKind::ARRAY:
1103+
{
1104+
auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
1105+
auto cap_tree = array_ty->get_capacity ()->get_value ();
1106+
size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
1107+
element_index = cap_wi - items.get_upper_patterns ().size ();
1108+
for (auto &pattern_member : items.get_upper_patterns ())
1109+
{
1110+
tree index_tree
1111+
= Backend::size_constant_expression (element_index++);
1112+
tree element_expr
1113+
= scrutinee_index_expr_func (match_scrutinee_expr,
1114+
index_tree,
1115+
pattern.get_locus ());
1116+
CompilePatternBindings::Compile (*pattern_member,
1117+
element_expr, ctx);
1118+
}
1119+
}
1120+
break;
1121+
case TyTy::TypeKind::SLICE:
1122+
rust_sorry_at (pattern.get_locus (),
1123+
"SlicePattern matching against non-ref slices are "
1124+
"not yet supported");
1125+
break;
1126+
case TyTy::TypeKind::REF:
1127+
{
1128+
tree slice_size
1129+
= Backend::struct_field_expression (match_scrutinee_expr, 1,
1130+
pattern.get_locus ());
1131+
tree upper_patterns_size = Backend::size_constant_expression (
1132+
items.get_upper_patterns ().size ());
1133+
tree index_tree = Backend::arithmetic_or_logical_expression (
1134+
ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
1135+
upper_patterns_size, pattern.get_locus ());
1136+
for (auto &pattern_member : items.get_upper_patterns ())
1137+
{
1138+
tree element_expr
1139+
= scrutinee_index_expr_func (match_scrutinee_expr,
1140+
index_tree,
1141+
pattern.get_locus ());
1142+
CompilePatternBindings::Compile (*pattern_member,
1143+
element_expr, ctx);
1144+
index_tree = Backend::arithmetic_or_logical_expression (
1145+
ArithmeticOrLogicalOperator::ADD, index_tree,
1146+
Backend::size_constant_expression (1),
1147+
pattern.get_locus ());
1148+
}
1149+
}
1150+
break;
1151+
default:
1152+
rust_unreachable ();
1153+
}
1154+
}
1155+
break;
9721156
}
9731157
}
9741158

gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,34 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
7070
return ty->as<TyTy::SliceType> ()->get_element_type ();
7171
});
7272

73-
// Regions are unchnaged.
73+
// Regions are unchanged.
7474

75-
for (auto &item : pattern.get_items ())
75+
switch (pattern.get_items ().get_item_type ())
7676
{
77-
item->accept_vis (*this);
77+
case HIR::SlicePatternItems::NO_REST:
78+
{
79+
auto &items
80+
= static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
81+
for (auto &member : items.get_patterns ())
82+
{
83+
member->accept_vis (*this);
84+
}
85+
break;
86+
}
87+
case HIR::SlicePatternItems::HAS_REST:
88+
{
89+
auto &items
90+
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
91+
for (auto &member : items.get_lower_patterns ())
92+
{
93+
member->accept_vis (*this);
94+
}
95+
for (auto &member : items.get_upper_patterns ())
96+
{
97+
member->accept_vis (*this);
98+
}
99+
break;
100+
}
78101
}
79102
}
80103

gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,14 @@ class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor
246246
rust_unreachable ();
247247
}
248248
void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); }
249+
void visit (HIR::SlicePatternItemsNoRest &tuple_items) override
250+
{
251+
rust_unreachable ();
252+
}
253+
void visit (HIR::SlicePatternItemsHasRest &tuple_items) override
254+
{
255+
rust_unreachable ();
256+
}
249257
void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); }
250258
void visit (HIR::AltPattern &pattern) override { rust_unreachable (); }
251259
void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); }

0 commit comments

Comments
 (0)