aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-01-18 21:42:53 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-01-20 09:59:22 +0000
commit4f6f18fe296d4729648eec0b77c8610f0b43445c (patch)
treea3897a28c43df3381df8bee90ab0a9501f32dd68
parent12f7bd0fc4e9ab4e98869b5265aea6bacfb31d03 (diff)
downloadgcc-4f6f18fe296d4729648eec0b77c8610f0b43445c.zip
gcc-4f6f18fe296d4729648eec0b77c8610f0b43445c.tar.gz
gcc-4f6f18fe296d4729648eec0b77c8610f0b43445c.tar.bz2
Support struct base reference in constructors
This creates implicit FieldAccessExpr or TupleIndexExprs for the missing fields in the constructor using the base struct as the receiver.
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h10
-rw-r--r--gcc/rust/hir/tree/rust-hir.h6
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h8
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc115
-rw-r--r--gcc/rust/typecheck/rust-tyty.h9
-rw-r--r--gcc/testsuite/rust.test/compilable/struct_init_4.rs9
-rw-r--r--gcc/testsuite/rust.test/compilable/struct_init_5.rs9
-rw-r--r--gcc/testsuite/rust.test/compilable/struct_init_6.rs9
8 files changed, 156 insertions, 19 deletions
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index ff3fbab..29b5691 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -1669,6 +1669,16 @@ public:
}
}
+ std::vector<std::unique_ptr<StructExprField> > &get_fields ()
+ {
+ return fields;
+ };
+
+ const std::vector<std::unique_ptr<StructExprField> > &get_fields () const
+ {
+ return fields;
+ };
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h
index 5d758ee..fabc31d 100644
--- a/gcc/rust/hir/tree/rust-hir.h
+++ b/gcc/rust/hir/tree/rust-hir.h
@@ -819,6 +819,9 @@ public:
const Analysis::NodeMapping &get_mappings () const { return mappings; }
+ // Clone function implementation as pure virtual method
+ virtual Expr *clone_expr_impl () const = 0;
+
protected:
// Constructor
Expr (Analysis::NodeMapping mappings,
@@ -826,9 +829,6 @@ protected:
: outer_attrs (std::move (outer_attribs)), mappings (std::move (mappings))
{}
- // Clone function implementation as pure virtual method
- virtual Expr *clone_expr_impl () const = 0;
-
// TODO: think of less hacky way to implement this kind of thing
// Sets outer attributes.
void set_outer_attrs (std::vector<Attribute> outer_attrs_to_set)
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 91ed6e0..181124a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -179,6 +179,14 @@ public:
{
ResolveExpr::go (&struct_expr.get_struct_name (),
struct_expr.get_node_id ());
+
+ if (struct_expr.has_struct_base ())
+ {
+ AST::StructBase &base = struct_expr.get_struct_base ();
+ ResolveExpr::go (base.get_base_struct ().get (),
+ struct_expr.get_node_id ());
+ }
+
struct_expr.iterate (
[&] (AST::StructExprField *struct_field) mutable -> bool {
ResolveStructExprField::go (struct_field, struct_expr.get_node_id ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index 6f8c3a1..4c09992 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -89,6 +89,22 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
return;
}
+ resolved = struct_path_resolved;
+ if (struct_expr.has_struct_base ())
+ {
+ TyTy::TyBase *base_resolved
+ = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
+ resolved = struct_path_resolved->combine (base_resolved);
+ if (resolved == nullptr)
+ {
+ rust_fatal_error (
+ struct_expr.struct_base->base_struct->get_locus_slow (),
+ "incompatible types for base struct reference");
+ return;
+ }
+ }
+
+ bool ok = true;
struct_expr.iterate ([&] (HIR::StructExprField *field) mutable -> bool {
resolved_field = nullptr;
field->accept_vis (*this);
@@ -96,6 +112,7 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
{
rust_fatal_error (field->get_locus (),
"failed to resolve type for field");
+ ok = false;
return false;
}
@@ -103,28 +120,94 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
return true;
});
- TyTy::TyBase *expr_type = struct_path_resolved;
- if (struct_expr.has_struct_base ())
+ // something failed setting up the fields
+ if (!ok)
+ return;
+
+ // check the arguments are all assigned and fix up the ordering
+ if (fields_assigned.size () != struct_path_resolved->num_fields ())
{
- TyTy::TyBase *base_resolved
- = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
- expr_type = expr_type->combine (base_resolved);
- if (resolved == nullptr)
+ if (!struct_expr.has_struct_base ())
{
- rust_fatal_error (
- struct_expr.struct_base->base_struct->get_locus_slow (),
- "incompatible types for base struct reference");
+ rust_error_at (struct_expr.get_locus (),
+ "constructor is missing fields");
return;
}
+ else
+ {
+ // we have a struct base to assign the missing fields from.
+ // the missing fields can be implicit FieldAccessExprs for the value
+ std::set<std::string> missing_fields;
+ struct_path_resolved->iterate_fields (
+ [&] (TyTy::StructFieldType *field) mutable -> bool {
+ auto it = fields_assigned.find (field->get_name ());
+ if (it == fields_assigned.end ())
+ missing_fields.insert (field->get_name ());
+ return true;
+ });
+
+ // we can generate FieldAccessExpr or TupleAccessExpr for the values
+ // of the missing fields.
+ for (auto &missing : missing_fields)
+ {
+ HIR::Expr *receiver
+ = struct_expr.struct_base->base_struct->clone_expr_impl ();
+
+ HIR::StructExprField *implicit_field = nullptr;
+ if (struct_path_resolved->is_tuple_struct ())
+ {
+ std::vector<HIR::Attribute> outer_attribs;
+ TupleIndex tuple_index = std::stoi (missing);
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (
+ crate_num,
+ struct_expr.struct_base->base_struct->get_mappings ()
+ .get_nodeid (),
+ mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ HIR::Expr *field_value = new HIR::TupleIndexExpr (
+ mapping, std::unique_ptr<HIR::Expr> (receiver), tuple_index,
+ std::move (outer_attribs),
+ struct_expr.struct_base->base_struct->get_locus_slow ());
+
+ implicit_field = new HIR::StructExprFieldIndexValue (
+ mapping, tuple_index,
+ std::unique_ptr<HIR::Expr> (field_value),
+ struct_expr.struct_base->base_struct->get_locus_slow ());
+ }
+ else
+ {
+ std::vector<HIR::Attribute> outer_attribs;
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (
+ crate_num,
+ struct_expr.struct_base->base_struct->get_mappings ()
+ .get_nodeid (),
+ mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ HIR::Expr *field_value = new HIR::FieldAccessExpr (
+ mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
+ std::move (outer_attribs),
+ struct_expr.struct_base->base_struct->get_locus_slow ());
+
+ implicit_field = new HIR::StructExprFieldIdentifierValue (
+ mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
+ struct_expr.struct_base->base_struct->get_locus_slow ());
+ }
+
+ struct_expr.get_fields ().push_back (
+ std::unique_ptr<HIR::StructExprField> (implicit_field));
+ }
+ }
}
- else if (fields_assigned.size () != struct_path_resolved->num_fields ())
- {
- rust_fatal_error (struct_expr.get_locus (),
- "some fields are not fully assigned");
- return;
- }
- resolved = expr_type;
+ // everything is ok, now we need to ensure all field values are ordered
+ // correctly. The GIMPLE backend uses a simple algorithm that assumes each
+ // assigned field in the constructor is in the same order as the field in the
+ // type
+
+ // TODO
}
void
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index b0ccf24..c32ac02 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -219,6 +219,15 @@ public:
std::vector<StructFieldType *> &get_fields () { return fields; }
const std::vector<StructFieldType *> &get_fields () const { return fields; }
+ void iterate_fields (std::function<bool (StructFieldType *)> cb)
+ {
+ for (auto &f : fields)
+ {
+ if (!cb (f))
+ return;
+ }
+ }
+
private:
std::string identifier;
bool is_tuple;
diff --git a/gcc/testsuite/rust.test/compilable/struct_init_4.rs b/gcc/testsuite/rust.test/compilable/struct_init_4.rs
new file mode 100644
index 0000000..2cc8a19
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/struct_init_4.rs
@@ -0,0 +1,9 @@
+struct Foo {
+ a: i32,
+ b: i32,
+}
+
+fn main() {
+ let a = Foo { a: 1, b: 2 };
+ let b = Foo { a: 3, b: 4, ..a };
+}
diff --git a/gcc/testsuite/rust.test/compilable/struct_init_5.rs b/gcc/testsuite/rust.test/compilable/struct_init_5.rs
new file mode 100644
index 0000000..c79ea71
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/struct_init_5.rs
@@ -0,0 +1,9 @@
+struct Foo {
+ a: i32,
+ b: i32,
+}
+
+fn main() {
+ let a = Foo { a: 1, b: 2 };
+ let b = Foo { ..a };
+}
diff --git a/gcc/testsuite/rust.test/compilable/struct_init_6.rs b/gcc/testsuite/rust.test/compilable/struct_init_6.rs
new file mode 100644
index 0000000..51b90bc
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/struct_init_6.rs
@@ -0,0 +1,9 @@
+struct Foo {
+ a: i32,
+ b: i32,
+}
+
+fn main() {
+ let a = Foo { a: 1, b: 2 };
+ let b = Foo { a: 1, ..a };
+}