aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2023-05-17 12:17:58 +0200
committerCohenArthur <arthur.cohen@embecosm.com>2023-06-01 15:32:23 +0000
commit2e49323c7593404ce536040b65bed37d4048eb95 (patch)
tree7d9d247f44d9a5301c9ad31d008d60470a03962e /gcc
parent7ffe13507fc3f125766e0fa5f9d0a4a47e5cce4c (diff)
downloadgcc-2e49323c7593404ce536040b65bed37d4048eb95.zip
gcc-2e49323c7593404ce536040b65bed37d4048eb95.tar.gz
gcc-2e49323c7593404ce536040b65bed37d4048eb95.tar.bz2
derive: Add #[derive(Clone)] for regular structs
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast-builder.cc24
-rw-r--r--gcc/rust/ast/rust-ast-builder.h15
-rw-r--r--gcc/rust/expand/rust-derive-clone.cc17
-rw-r--r--gcc/testsuite/rust/execute/torture/derive_macro4.rs29
4 files changed, 82 insertions, 3 deletions
diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc
index 0611654..d37f143 100644
--- a/gcc/rust/ast/rust-ast-builder.cc
+++ b/gcc/rust/ast/rust-ast-builder.cc
@@ -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
diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h
index 4bbd931..1c524b4 100644
--- a/gcc/rust/ast/rust-ast-builder.h
+++ b/gcc/rust/ast/rust-ast-builder.h
@@ -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
diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc
index b641484..176cee9 100644
--- a/gcc/rust/expand/rust-derive-clone.cc
+++ b/gcc/rust/expand/rust-derive-clone.cc
@@ -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
index 0000000..218bf61
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/derive_macro4.rs
@@ -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