aboutsummaryrefslogtreecommitdiff
path: root/gcc
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 /gcc
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.
Diffstat (limited to 'gcc')
-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 };
+}