https://gcc.gnu.org/g:e80e577df7ca410eac549da61f9a9fd702dc55ea
commit r16-2960-ge80e577df7ca410eac549da61f9a9fd702dc55ea Author: Yap Zhi Heng <yapz...@gmail.com> Date: Wed Jul 23 08:24:18 2025 +0800 gccrs: Implement compilation for SlicePattern against SliceType scrutinee 006t.original output from compiling testsuite/rust/compile/match-slicepattern-slice.rs: ... RUSTTMP.3 = slice; if (RUSTTMP.3.len == 1 && *(RUSTTMP.3.data + 0 * 4) == 1) { { struct () RUSTTMP.4; { } goto <D.129>; } } if (RUSTTMP.3.len == 2 && *(RUSTTMP.3.data + 1 * 4) == 2) { { struct () RUSTTMP.5; { } goto <D.129>; } } if (1) { { struct () RUSTTMP.6; { } goto <D.129>; } } <D.129>:; ... gcc/rust/ChangeLog: * rust-backend.h: New slice_index_expression function. * rust-gcc.cc: Implementation of slice_index_expression to generate tree node for accessing slice elements. * backend/rust-compile-pattern.cc: Implement SlicePattern check expression & binding compilation against SliceType scrutinee. Signed-off-by: Yap Zhi Heng <yapz...@gmail.com> Diff: --- gcc/rust/backend/rust-compile-pattern.cc | 50 +++++++++++++++++++++- gcc/rust/rust-backend.h | 4 ++ gcc/rust/rust-gcc.cc | 28 ++++++++++++ .../rust/compile/match-slicepattern-slice.rs | 10 +++++ .../execute/torture/match-slicepattern-slice-1.rs | 24 +++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index e00de4f467f3..fe6592174382 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -555,7 +555,38 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) case TyTy::TypeKind::SLICE: rust_sorry_at ( pattern.get_locus (), - "SlicePattern matching against slices are not yet supported"); + "SlicePattern matching against non-ref slices are not yet supported"); + break; + case TyTy::TypeKind::REF: + { + rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr))); + 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 ()); + + // Then compare each element in the slice pattern + for (auto &pattern_member : pattern.get_items ()) + { + tree slice_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::slice_index_expression (match_scrutinee_expr, + slice_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; default: rust_unreachable (); @@ -917,8 +948,23 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern) case TyTy::TypeKind::SLICE: rust_sorry_at ( pattern.get_locus (), - "SlicePattern matching against slices are not yet supported"); + "SlicePattern matching against non-ref slices are not yet supported"); break; + case TyTy::TypeKind::REF: + { + for (auto &pattern_member : pattern.get_items ()) + { + tree slice_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::slice_index_expression (match_scrutinee_expr, + slice_index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, element_expr, + ctx); + } + break; + } default: rust_unreachable (); } diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 8a77d96de835..205eb2b71465 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -245,6 +245,10 @@ tree array_initializer (tree, tree, tree, tree, tree, tree *, location_t); // fixed-length array, not a slice. tree array_index_expression (tree array, tree index, location_t); +// Return an expresison for SLICE[INDEX] as an l-value. SLICE is represented +// with a DST. +tree slice_index_expression (tree slice, tree index, location_t); + // Create an expression for a call to FN with ARGS, taking place within // caller CALLER. tree call_expression (tree fn, const std::vector<tree> &args, tree static_chain, diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index c5fda5c7a9ca..0f9ccfb9c81a 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -1504,6 +1504,34 @@ array_index_expression (tree array_tree, tree index_tree, location_t location) return ret; } +// Return an expression representing SLICE[INDEX] + +tree +slice_index_expression (tree slice_tree, tree index_tree, location_t location) +{ + if (error_operand_p (slice_tree) || error_operand_p (index_tree)) + return error_mark_node; + + // A slice is created in TyTyResolvecompile::create_slice_type_record + // For example: + // &[i32] is turned directly into a struct { i32* data, usize len }; + // [i32] is also turned into struct { i32* data, usize len } + + // it should have RS_DST_FLAG set to 1 + rust_assert (RS_DST_FLAG_P (TREE_TYPE (slice_tree))); + + tree data_field = struct_field_expression (slice_tree, 0, location); + tree data_field_deref = build_fold_indirect_ref_loc (location, data_field); + + tree element_type = TREE_TYPE (data_field_deref); + tree data_pointer = TREE_OPERAND (data_field_deref, 0); + rust_assert (POINTER_TYPE_P (TREE_TYPE (data_pointer))); + tree data_offset_expr + = Rust::pointer_offset_expression (data_pointer, index_tree, location); + + return build1_loc (location, INDIRECT_REF, element_type, data_offset_expr); +} + // Create an expression for a call to FN_EXPR with FN_ARGS. tree call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr, diff --git a/gcc/testsuite/rust/compile/match-slicepattern-slice.rs b/gcc/testsuite/rust/compile/match-slicepattern-slice.rs new file mode 100644 index 000000000000..cc33d938c7be --- /dev/null +++ b/gcc/testsuite/rust/compile/match-slicepattern-slice.rs @@ -0,0 +1,10 @@ +fn main() { + let arr = [1, 2]; + let slice: &[i32] = &arr; + + match slice { + [1] => {}, + [_, 2] => {}, + _ => {} + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs new file mode 100644 index 000000000000..3ed0b644fb7e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs @@ -0,0 +1,24 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let arr = [0, 1]; + let a: &[i32] = &arr; + let mut ret = 1; + + match a { + [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 +}