aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/expand/rust-derive-clone.cc85
-rw-r--r--gcc/testsuite/rust/compile/derive_clone_enum1.rs16
-rw-r--r--gcc/testsuite/rust/compile/derive_clone_enum2.rs16
-rw-r--r--gcc/testsuite/rust/compile/derive_clone_enum3.rs16
-rw-r--r--gcc/testsuite/rust/compile/nr2/exclude3
-rw-r--r--gcc/testsuite/rust/execute/torture/derive_clone_enum1.rs51
6 files changed, 180 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
diff --git a/gcc/testsuite/rust/compile/derive_clone_enum1.rs b/gcc/testsuite/rust/compile/derive_clone_enum1.rs
new file mode 100644
index 0000000..947dc5c6
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive_clone_enum1.rs
@@ -0,0 +1,16 @@
+#[lang = "clone"]
+trait Clone {
+ pub fn clone(&self) -> Self;
+}
+
+impl Clone for i32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[derive(Clone)]
+enum AllIdentifiers {
+ A,
+ B
+}
diff --git a/gcc/testsuite/rust/compile/derive_clone_enum2.rs b/gcc/testsuite/rust/compile/derive_clone_enum2.rs
new file mode 100644
index 0000000..c7a4ad5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive_clone_enum2.rs
@@ -0,0 +1,16 @@
+#[lang = "clone"]
+trait Clone {
+ pub fn clone(&self) -> Self;
+}
+
+impl Clone for i32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[derive(Clone)]
+enum TupleEnum {
+ A(i32),
+ B(i32, i32, i32)
+}
diff --git a/gcc/testsuite/rust/compile/derive_clone_enum3.rs b/gcc/testsuite/rust/compile/derive_clone_enum3.rs
new file mode 100644
index 0000000..92fd6ee
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive_clone_enum3.rs
@@ -0,0 +1,16 @@
+#[lang = "clone"]
+trait Clone {
+ pub fn clone(&self) -> Self;
+}
+
+impl Clone for i32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[derive(Clone)]
+enum StructEnum {
+ A { i0: i32 },
+ B { i0: i32, i1: i32, i2: i32 }
+}
diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude
index 0f482df..1a9c8e7 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -143,4 +143,7 @@ additional-trait-bounds2.rs
auto_traits3.rs
issue-3140.rs
cmp1.rs
+derive_clone_enum1.rs
+derive_clone_enum2.rs
+derive_clone_enum3.rs
# please don't delete the trailing newline
diff --git a/gcc/testsuite/rust/execute/torture/derive_clone_enum1.rs b/gcc/testsuite/rust/execute/torture/derive_clone_enum1.rs
new file mode 100644
index 0000000..542ecd8
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/derive_clone_enum1.rs
@@ -0,0 +1,51 @@
+#[lang = "clone"]
+trait Clone {
+ pub fn clone(&self) -> Self;
+}
+
+impl Clone for i32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[derive(Clone)]
+enum MixAndMatch {
+ A,
+ B(i32),
+ C { inner: i32 }
+}
+
+fn main() -> i32 {
+ let a = MixAndMatch::A;
+ let a_copy = a.clone();
+
+ // we want res to stay at zero - when we don't match on the right thing, increase it
+
+ let mut res = match a_copy {
+ MixAndMatch::A => 0,
+ _ => 1,
+ };
+
+ let a = MixAndMatch::B(15);
+ let a_copy = a.clone();
+
+ match a_copy {
+ MixAndMatch::B(15) => {},
+ _ => res += 1,
+ };
+
+ let a = MixAndMatch::C { inner: 15 };
+ let a_copy = a.clone();
+
+ match a_copy {
+ MixAndMatch::C { inner } => {
+ if inner != 15 {
+ res += 1;
+ }
+ },
+ _ => res += 1,
+ };
+
+ res
+}