https://gcc.gnu.org/g:515e1692ffe87852ae68fab2715a64e6bf0477a2

commit 515e1692ffe87852ae68fab2715a64e6bf0477a2
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Wed Apr 16 16:32:35 2025 +0200

    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.

Diff:
---
 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(-)

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<HIR::StructPatternFieldIdent &> (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<HIR::StructPatternFieldIdent &> (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<HIR::StructPatternFieldIdentPat &> (pat);
+
+  switch (pattern.get_pattern ().get_pattern_type ())
+    {
+      case HIR::Pattern::IDENTIFIER: {
+       auto &id
+         = static_cast<HIR::IdentifierPattern &> (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 @@ public:
     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
+}

Reply via email to