From ef547ecd0c77073ab6c59419a0a04cc288410940 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 16 Apr 2025 16:03:26 +0200 Subject: [PATCH 1/3] backend: Refactor struct pattern compilation gcc/rust/ChangeLog: * backend/rust-compile-pattern.h: Split struct pattern compilation into three functions. * backend/rust-compile-pattern.cc: Implement them. --- gcc/rust/backend/rust-compile-pattern.cc | 105 +++++++++++++---------- gcc/rust/backend/rust-compile-pattern.h | 9 ++ 2 files changed, 68 insertions(+), 46 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 1e33c4899634..a83607294e19 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -22,6 +22,8 @@ #include "rust-constexpr.h" #include "rust-compile-type.h" #include "print-tree.h" +#include "rust-hir-pattern.h" +#include "rust-system.h" namespace Rust { namespace Compile { @@ -504,6 +506,57 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) } } +void +CompilePatternBindings::handle_struct_pattern_ident ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + HIR::StructPatternFieldIdent &ident + = static_cast (pat); + + size_t offs = 0; + auto ok = variant->lookup_field (ident.get_identifier ().as_string (), + nullptr, &offs); + rust_assert (ok); + + tree binding = error_mark_node; + if (adt->is_enum ()) + { + tree payload_accessor_union + = Backend::struct_field_expression (match_scrutinee_expr, 1, + ident.get_locus ()); + + tree variant_accessor + = Backend::struct_field_expression (payload_accessor_union, + variant_index, ident.get_locus ()); + + binding = Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } + else + { + tree variant_accessor = match_scrutinee_expr; + binding = Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } + + ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding); +} + +void +CompilePatternBindings::handle_struct_pattern_ident_pat ( + HIR::StructPatternField &pat) +{ + rust_unreachable (); +} + +void +CompilePatternBindings::handle_struct_pattern_tuple_pat ( + HIR::StructPatternField &pat) +{ + rust_unreachable (); +} + void CompilePatternBindings::visit (HIR::StructPattern &pattern) { @@ -539,54 +592,14 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::TUPLE_PAT: + handle_struct_pattern_tuple_pat (*field); break; - - case HIR::StructPatternField::ItemType::IDENT_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::IDENT_PAT: + handle_struct_pattern_ident_pat (*field); break; - - case HIR::StructPatternField::ItemType::IDENT: { - HIR::StructPatternFieldIdent &ident - = static_cast (*field.get ()); - - size_t offs = 0; - ok = variant->lookup_field (ident.get_identifier ().as_string (), - nullptr, &offs); - rust_assert (ok); - - tree binding = error_mark_node; - if (adt->is_enum ()) - { - tree payload_accessor_union - = Backend::struct_field_expression (match_scrutinee_expr, 1, - ident.get_locus ()); - - tree variant_accessor - = Backend::struct_field_expression (payload_accessor_union, - variant_index, - ident.get_locus ()); - - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - else - { - tree variant_accessor = match_scrutinee_expr; - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - - ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), - binding); - } + case HIR::StructPatternField::ItemType::IDENT: + handle_struct_pattern_ident (*field, adt, variant, variant_index); break; } } diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index fc12859a4646..dea63e3ca346 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -17,7 +17,9 @@ // . #include "rust-compile-base.h" +#include "rust-hir-pattern.h" #include "rust-hir-visitor.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -78,6 +80,13 @@ class CompilePatternBindings : public HIRCompileBase, pattern.accept_vis (compiler); } + void handle_struct_pattern_ident (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); + void handle_struct_pattern_ident_pat (HIR::StructPatternField &pat); + void handle_struct_pattern_tuple_pat (HIR::StructPatternField &pat); + void visit (HIR::StructPattern &pattern) override; void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::ReferencePattern &pattern) override; From b83427564ccbfd5418555d1fdf4457c49dd95868 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 16 Apr 2025 16:32:35 +0200 Subject: [PATCH 2/3] backend: Compile struct rebinding patterns Allow matching on a struct instance and rebinding its fields to new names: match X { Foo { field0: new_name0, field1: new_name1, } => { do_something(new_name0, new_name1); }, } This will enable us to finish derives for PartialEq and PartialOrd but isn't a complete implementation of these patterns yet. gcc/rust/ChangeLog: * backend/rust-compile-pattern.cc (CompilePatternBindings::make_struct_access): New function. (CompilePatternBindings::visit): Properly implement patterns mentioned above and call make_struct_accesss. * backend/rust-compile-pattern.h: New declaration. gcc/testsuite/ChangeLog: * rust/execute/torture/struct_pattern1.rs: New test. --- gcc/rust/backend/rust-compile-pattern.cc | 68 ++++++++++++++----- gcc/rust/backend/rust-compile-pattern.h | 8 ++- .../rust/execute/torture/struct_pattern1.rs | 19 ++++++ 3 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/struct_pattern1.rs diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index a83607294e19..94844fed2e84 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -22,8 +22,11 @@ #include "rust-constexpr.h" #include "rust-compile-type.h" #include "print-tree.h" +#include "rust-diagnostics.h" +#include "rust-hir-pattern-abstract.h" #include "rust-hir-pattern.h" #include "rust-system.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -506,20 +509,16 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) } } -void -CompilePatternBindings::handle_struct_pattern_ident ( - HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, - int variant_index) +tree +CompilePatternBindings::make_struct_access (TyTy::ADTType *adt, + TyTy::VariantDef *variant, + Identifier &ident, + int variant_index) { - HIR::StructPatternFieldIdent &ident - = static_cast (pat); - size_t offs = 0; - auto ok = variant->lookup_field (ident.get_identifier ().as_string (), - nullptr, &offs); + auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs); rust_assert (ok); - tree binding = error_mark_node; if (adt->is_enum ()) { tree payload_accessor_union @@ -530,24 +529,59 @@ CompilePatternBindings::handle_struct_pattern_ident ( = Backend::struct_field_expression (payload_accessor_union, variant_index, ident.get_locus ()); - binding = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); } else { tree variant_accessor = match_scrutinee_expr; - binding = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); + + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); } +} + +void +CompilePatternBindings::handle_struct_pattern_ident ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + HIR::StructPatternFieldIdent &ident + = static_cast (pat); + + auto identifier = ident.get_identifier (); + tree binding = make_struct_access (adt, variant, identifier, variant_index); ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding); } void CompilePatternBindings::handle_struct_pattern_ident_pat ( - HIR::StructPatternField &pat) + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) { - rust_unreachable (); + auto &pattern = static_cast (pat); + + switch (pattern.get_pattern ().get_pattern_type ()) + { + case HIR::Pattern::IDENTIFIER: { + auto &id + = static_cast (pattern.get_pattern ()); + + CompilePatternBindings::Compile (id, match_scrutinee_expr, ctx); + } + break; + default: + rust_sorry_at (pat.get_locus (), + "cannot handle non-identifier struct patterns"); + return; + } + + auto ident = pattern.get_identifier (); + tree binding = make_struct_access (adt, variant, ident, variant_index); + + ctx->insert_pattern_binding ( + pattern.get_pattern ().get_mappings ().get_hirid (), binding); } void @@ -596,7 +630,7 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) handle_struct_pattern_tuple_pat (*field); break; case HIR::StructPatternField::ItemType::IDENT_PAT: - handle_struct_pattern_ident_pat (*field); + handle_struct_pattern_ident_pat (*field, adt, variant, variant_index); break; case HIR::StructPatternField::ItemType::IDENT: handle_struct_pattern_ident (*field, adt, variant, variant_index); diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index dea63e3ca346..8ebc2755c490 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -80,11 +80,17 @@ class CompilePatternBindings : public HIRCompileBase, pattern.accept_vis (compiler); } + tree make_struct_access (TyTy::ADTType *adt, TyTy::VariantDef *variant, + Identifier &ident, int variant_index); + void handle_struct_pattern_ident (HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, int variant_index); - void handle_struct_pattern_ident_pat (HIR::StructPatternField &pat); + void handle_struct_pattern_ident_pat (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); void handle_struct_pattern_tuple_pat (HIR::StructPatternField &pat); void visit (HIR::StructPattern &pattern) override; diff --git a/gcc/testsuite/rust/execute/torture/struct_pattern1.rs b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs new file mode 100644 index 000000000000..7a74092ad50c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs @@ -0,0 +1,19 @@ +struct A { + // the two warnings are invalid but this should be fixed by our lint rework + // with this year's GSoC so ok for now + a: i32, // { dg-warning "never read" } + b: i32, // { dg-warning "never read" } +} + +fn main() -> i32 { + let a = A { a: 15, b: 14 }; + + let result = match a { + A { + a: self_a, + b: self_b, + } => self_a + self_b, + }; + + result - 29 +} From f7e5f6651412b978f1eae469703ebee64f976cd1 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 16 Apr 2025 17:39:28 +0200 Subject: [PATCH 3/3] backend: Remove checks on StructFieldIdentPattern gcc/rust/ChangeLog: * backend/rust-compile-pattern.cc (CompilePatternCheckExpr::visit): Remove old invalid checks. --- gcc/rust/backend/rust-compile-pattern.cc | 32 ++++++------------------ 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 94844fed2e84..671025ae8598 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -259,34 +259,16 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { - HIR::StructPatternFieldIdentPat &ident - = static_cast (*field.get ()); - - size_t offs = 0; - ok = variant->lookup_field (ident.get_identifier ().as_string (), - nullptr, &offs); - rust_assert (ok); - - // we may be offsetting by + 1 here since the first field in the - // record is always the discriminator - offs += adt->is_enum (); - tree field_expr - = Backend::struct_field_expression (match_scrutinee_expr, offs, - ident.get_locus ()); + case HIR::StructPatternField::ItemType::IDENT_PAT: + // we only support rebinding patterns at the moment, which always + // match - so do nothing - tree check_expr_sub - = CompilePatternCheckExpr::Compile (ident.get_pattern (), - field_expr, ctx); - check_expr = Backend::arithmetic_or_logical_expression ( - ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, - check_expr_sub, ident.get_pattern ().get_locus ()); - } + // this needs to change once we actually check that the field + // matches a certain value, either a literal value or a const one break; - case HIR::StructPatternField::ItemType::IDENT: { - // ident pattern always matches - do nothing - } + case HIR::StructPatternField::ItemType::IDENT: + // ident pattern always matches - do nothing break; } }