From: Arthur Cohen Date: Wed, 17 May 2023 10:17:58 +0000 (+0200) Subject: gccrs: derive: Add #[derive(Clone)] for regular structs X-Git-Tag: basepoints/gcc-15~2501 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=525e987ae8d2245c2bdd25a2cafd07e8f4bbe0ec;p=thirdparty%2Fgcc.git gccrs: 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. --- diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc index 06116540c194..d37f143ca34a 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 &&of) return std::unique_ptr (new DereferenceExpr (std::move (of), {}, loc)); } +std::unique_ptr +AstBuilder::struct_expr (std::string struct_name, + std::vector> &&fields) +{ + return std::unique_ptr ( + new StructExprStructFields (path_in_expression ({struct_name}), + std::move (fields), loc)); +} + +std::unique_ptr +AstBuilder::struct_expr_field (std::string field_name, + std::unique_ptr &&value) +{ + return std::unique_ptr ( + new StructExprFieldIdentifierValue (field_name, std::move (value), loc)); +} + +std::unique_ptr +AstBuilder::field_access (std::unique_ptr &&instance, std::string field) +{ + return std::unique_ptr ( + 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 4bbd931a7f97..1c524b438d83 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 struct_expr_struct (std::string struct_name); + /** + * Create an expression for struct instantiation with fields (`S { a, b: c }`) + */ + std::unique_ptr + struct_expr (std::string struct_name, + std::vector> &&fields); + + /* Create a field expression for struct instantiation (`field_name: value`) */ + std::unique_ptr + struct_expr_field (std::string field_name, std::unique_ptr &&value); + + /* Create a field access expression (`instance.field`) */ + std::unique_ptr field_access (std::unique_ptr &&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 b64148431553..176cee9b7497 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> (); + 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 000000000000..218bf617bd6d --- /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