]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: derive: Add #[derive(Clone)] for regular structs
authorArthur Cohen <arthur.cohen@embecosm.com>
Wed, 17 May 2023 10:17:58 +0000 (12:17 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:46:23 +0000 (18:46 +0100)
gcc/rust/ChangeLog:

* expand/rust-derive-clone.cc (DeriveClone::visit_struct): Implement proper
cloning for structs with fields.
* ast/rust-ast-builder.cc (AstBuilder::struct_expr): New function.
(AstBuilder::struct_expr_field): Likewise.
(AstBuilder::field_access): Likewise.
(AstBuilder::let): Likewise.
* ast/rust-ast-builder.h: Declare new functions.

gcc/testsuite/ChangeLog:

* rust/execute/torture/derive_macro4.rs: New test.

gcc/rust/ast/rust-ast-builder.cc
gcc/rust/ast/rust-ast-builder.h
gcc/rust/expand/rust-derive-clone.cc
gcc/testsuite/rust/execute/torture/derive_macro4.rs [new file with mode: 0644]

index 06116540c194122fedb4127d40218a647da019ba..d37f143ca34a4d4c7e2ff4485ae133c1f2f9813c 100644 (file)
@@ -118,5 +118,29 @@ AstBuilder::deref (std::unique_ptr<Expr> &&of)
   return std::unique_ptr<Expr> (new DereferenceExpr (std::move (of), {}, loc));
 }
 
+std::unique_ptr<Expr>
+AstBuilder::struct_expr (std::string struct_name,
+                        std::vector<std::unique_ptr<StructExprField>> &&fields)
+{
+  return std::unique_ptr<Expr> (
+    new StructExprStructFields (path_in_expression ({struct_name}),
+                               std::move (fields), loc));
+}
+
+std::unique_ptr<StructExprField>
+AstBuilder::struct_expr_field (std::string field_name,
+                              std::unique_ptr<Expr> &&value)
+{
+  return std::unique_ptr<StructExprField> (
+    new StructExprFieldIdentifierValue (field_name, std::move (value), loc));
+}
+
+std::unique_ptr<Expr>
+AstBuilder::field_access (std::unique_ptr<Expr> &&instance, std::string field)
+{
+  return std::unique_ptr<Expr> (
+    new FieldAccessExpr (std::move (instance), field, {}, loc));
+}
+
 } // namespace AST
 } // namespace Rust
index 4bbd931a7f97d41612943b363a4147a2ace7a3a5..1c524b438d833f252519b0977b2bc1e265a424d3 100644 (file)
@@ -85,6 +85,21 @@ public:
   /* Create a struct expression for unit structs (`S`) */
   std::unique_ptr<Expr> struct_expr_struct (std::string struct_name);
 
+  /**
+   * Create an expression for struct instantiation with fields (`S { a, b: c }`)
+   */
+  std::unique_ptr<Expr>
+  struct_expr (std::string struct_name,
+              std::vector<std::unique_ptr<StructExprField>> &&fields);
+
+  /* Create a field expression for struct instantiation (`field_name: value`) */
+  std::unique_ptr<StructExprField>
+  struct_expr_field (std::string field_name, std::unique_ptr<Expr> &&value);
+
+  /* Create a field access expression (`instance.field`) */
+  std::unique_ptr<Expr> field_access (std::unique_ptr<Expr> &&instance,
+                                     std::string field);
+
 private:
   /**
    * Location of the generated AST nodes
index b6414843155341b164645b461aef2acd28722d8f..176cee9b7497ccdb93628c8c6719a407c28e25fb 100644 (file)
@@ -126,12 +126,23 @@ DeriveClone::visit_struct (StructStruct &item)
       auto unit_ctor = builder.struct_expr_struct (item.get_struct_name ());
       expanded = clone_impl (clone_fn (std::move (unit_ctor)),
                             item.get_struct_name ());
+      return;
     }
-  else
+
+  auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
+  for (auto &field : item.get_fields ())
     {
-      rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet",
-                    "Clone");
+      auto name = field.get_field_name ();
+      auto expr = clone_call (
+       builder.ref (builder.field_access (builder.identifier ("self"), name)));
+
+      cloned_fields.emplace_back (
+       builder.struct_expr_field (std::move (name), std::move (expr)));
     }
+
+  auto ctor
+    = builder.struct_expr (item.get_struct_name (), std::move (cloned_fields));
+  expanded = clone_impl (clone_fn (std::move (ctor)), item.get_struct_name ());
 }
 
 void
diff --git a/gcc/testsuite/rust/execute/torture/derive_macro4.rs b/gcc/testsuite/rust/execute/torture/derive_macro4.rs
new file mode 100644 (file)
index 0000000..218bf61
--- /dev/null
@@ -0,0 +1,29 @@
+pub trait Clone {
+    fn clone(&self) -> Self;
+}
+
+#[derive(Clone)]
+struct Foo {
+    a: i32,
+}
+
+#[derive(Clone)]
+struct S {
+    a: i32,
+    b: Foo,
+}
+
+impl Clone for i32 {
+    fn clone(&self) -> Self { *self }
+}
+
+fn main() -> i32 {
+    let s1 = S { a: 15, b: Foo { a: 14 }};
+    let s2 = s1.clone();
+
+    let l = s1.a - s2.a;
+    let r = s1.b.a - s2.b.a;
+
+    // should be 0 if all fields were cloned correctly
+    l + r
+}
\ No newline at end of file