From: Yap Zhi Heng <[email protected]>
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 <[email protected]>
---
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 ++++
.../torture/match-slicepattern-slice-1.rs | 24 +++++++++
5 files changed, 114 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/match-slicepattern-slice.rs
create mode 100644
gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs
diff --git a/gcc/rust/backend/rust-compile-pattern.cc
b/gcc/rust/backend/rust-compile-pattern.cc
index e00de4f467f..fe659217438 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 8a77d96de83..205eb2b7146 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 c5fda5c7a9c..0f9ccfb9c81 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 00000000000..cc33d938c7b
--- /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 00000000000..3ed0b644fb7
--- /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
+}
--
2.49.0