diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2025-01-03 15:14:45 +0000 |
---|---|---|
committer | CohenArthur <arthur.cohen@embecosm.com> | 2025-01-20 12:09:26 +0000 |
commit | f027f0a605b58b495878fde922a5b2eab08d6124 (patch) | |
tree | 51e5a9a25e23aa09c0cdbf92a3295ab8c389495e /gcc/rust | |
parent | 40574e5eb02fb0d607267f39e338dcbd53f650da (diff) | |
download | gcc-f027f0a605b58b495878fde922a5b2eab08d6124.zip gcc-f027f0a605b58b495878fde922a5b2eab08d6124.tar.gz gcc-f027f0a605b58b495878fde922a5b2eab08d6124.tar.bz2 |
derive(Clone): Implement derive clone for enum struct variants
gcc/rust/ChangeLog:
* expand/rust-derive-clone.cc (DeriveClone::clone_enum_struct): New function for deriving
enum struct variants.
(DeriveClone::visit_enum): Call into the new function.
gcc/testsuite/ChangeLog:
* rust/compile/nr2/exclude:
* rust/compile/derive_clone_enum1.rs: New test.
* rust/compile/derive_clone_enum2.rs: New test.
* rust/compile/derive_clone_enum3.rs: New test.
* rust/execute/torture/derive_clone_enum1.rs: New test.
Diffstat (limited to 'gcc/rust')
-rw-r--r-- | gcc/rust/expand/rust-derive-clone.cc | 85 |
1 files changed, 78 insertions, 7 deletions
diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc index 36fa529..e914d60 100644 --- a/gcc/rust/expand/rust-derive-clone.cc +++ b/gcc/rust/expand/rust-derive-clone.cc @@ -19,6 +19,7 @@ #include "rust-derive-clone.h" #include "rust-ast.h" #include "rust-ast-dump.h" +#include "rust-expr.h" #include "rust-item.h" #include "rust-path.h" #include "rust-pattern.h" @@ -300,13 +301,84 @@ DeriveClone::clone_enum_tuple (Enum &item, const EnumItemTuple &variant) return builder.match_case (std::move (pattern), std::move (expr)); } +MatchCase +DeriveClone::clone_enum_struct (Enum &item, const EnumItemStruct &variant) +{ + auto variant_path = variant_match_path (item, variant.get_identifier ()); + + auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> (); + auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> (); + +#if 0 + // NOTE: We currently do not support compiling struct patterns where an + // identifier is assigned a new pattern, e.g. Bloop { f0: x } + // This is the code we should eventually produce as it mimics what rustc does + // - which is probably here for a good reason. In the meantime, we can just + // use the field's identifier as the pattern: Bloop { f0 } + // We can then clone the field directly instead of calling `clone()` on the + // new pattern. + // TODO: Figure out if that is actually needed and why rustc does it? + + for (size_t i = 0; i < variant.get_struct_fields ().size (); i++) + { + auto &field = variant.get_struct_fields ()[i]; + + // Just like for tuples, the pattern we're creating for each field is + // `self_<i>` where `i` is the index of the field. It doesn't actually + // matter what we use, as long as it's ordered, unique, and that we can + // reuse it in the match case's return expression to clone the field. + auto pattern_str = "__self_" + std::to_string (i); + + field_patterns.emplace_back ( + std::unique_ptr<StructPatternField> (new StructPatternFieldIdentPat ( + field.get_field_name (), builder.identifier_pattern (pattern_str), {}, + loc))); + + cloned_fields.emplace_back ( + std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue ( + field.get_field_name (), + clone_call (builder.ref (builder.identifier (pattern_str))), {}, + loc))); + } +#endif + + for (const auto &field : variant.get_struct_fields ()) + { + // We match on the struct's fields, and then recreate an instance of that + // struct, cloning each field + + field_patterns.emplace_back ( + std::unique_ptr<StructPatternField> (new StructPatternFieldIdent ( + field.get_field_name (), false /* is_ref? true? */, false, {}, loc))); + + cloned_fields.emplace_back ( + std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue ( + field.get_field_name (), + clone_call (builder.ref ( + builder.identifier (field.get_field_name ().as_string ()))), + {}, loc))); + } + + auto pattern_elts = StructPatternElements (std::move (field_patterns)); + + auto pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, pattern_elts)), + false, false, loc)); + auto expr = std::unique_ptr<Expr> ( + new StructExprStructFields (variant_path, std::move (cloned_fields), loc)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + void DeriveClone::visit_enum (Enum &item) { - // Create an arm for each variant of the enum - // For enum item variants, just create the same variant - // For struct and tuple variants, destructure the pattern and call clone for - // each field + // Create an arm for each variant of the enum: + // - For enum item variants (simple identifiers), just create the same + // variant. + // - For struct and tuple variants, destructure the pattern and call clone for + // each field. auto cases = std::vector<MatchCase> (); @@ -325,7 +397,8 @@ DeriveClone::visit_enum (Enum &item) clone_enum_tuple (item, static_cast<EnumItemTuple &> (*variant))); break; case EnumItem::Kind::Struct: - rust_unreachable (); + cases.emplace_back ( + clone_enum_struct (item, static_cast<EnumItemStruct &> (*variant))); break; } } @@ -336,8 +409,6 @@ DeriveClone::visit_enum (Enum &item) expanded = clone_impl (clone_fn (std::move (match)), item.get_identifier ().as_string (), item.get_generic_params ()); - - AST::Dump::debug (*expanded); } void |