diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2023-05-17 12:17:58 +0200 |
---|---|---|
committer | CohenArthur <arthur.cohen@embecosm.com> | 2023-06-01 15:32:23 +0000 |
commit | 2e49323c7593404ce536040b65bed37d4048eb95 (patch) | |
tree | 7d9d247f44d9a5301c9ad31d008d60470a03962e /gcc | |
parent | 7ffe13507fc3f125766e0fa5f9d0a4a47e5cce4c (diff) | |
download | gcc-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.cc | 24 | ||||
-rw-r--r-- | gcc/rust/ast/rust-ast-builder.h | 15 | ||||
-rw-r--r-- | gcc/rust/expand/rust-derive-clone.cc | 17 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/derive_macro4.rs | 29 |
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 |