diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-09-13 16:31:18 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-09-13 16:33:58 +0100 |
commit | 9464066111c715a63e632b1dc60f3230e8c48bb1 (patch) | |
tree | b1bcaa2f68d4fc74e4e90ff6d608613e4f11a8a7 /gcc | |
parent | e3b7eb58844c446d097ddee00ecd455d5537c6b2 (diff) | |
download | gcc-9464066111c715a63e632b1dc60f3230e8c48bb1.zip gcc-9464066111c715a63e632b1dc60f3230e8c48bb1.tar.gz gcc-9464066111c715a63e632b1dc60f3230e8c48bb1.tar.bz2 |
Support indirection for struct and tuple field access
When we have a fat pointer to a structure the GCC needs to know the RECORD
or UNION type of the type before it can access fields, this can be
supported by C'stye indirection such as '->'.
This might get updated when we support the autoderef mechanism and if the
type supports the deref trait.
Addresses #241
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 51 | ||||
-rw-r--r-- | gcc/rust/lint/rust-lint-marklive.cc | 20 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 17 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/autoderef1.rs | 15 |
4 files changed, 92 insertions, 11 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index ac33ccd..d0c0b74 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -46,6 +46,26 @@ public: TupleIndex index = expr.get_tuple_index (); Bexpression *receiver_ref = CompileExpr::Compile (tuple_expr, ctx); + + TyTy::BaseType *tuple_expr_ty = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + tuple_expr->get_mappings ().get_hirid (), &tuple_expr_ty); + rust_assert (ok); + + // do we need to add an indirect reference + if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r + = static_cast<TyTy::ReferenceType *> (tuple_expr_ty); + TyTy::BaseType *tuple_type = r->get_base (); + Btype *tuple_tyty = TyTyResolveCompile::compile (ctx, tuple_type); + + Bexpression *indirect + = ctx->get_backend ()->indirect_expression (tuple_tyty, receiver_ref, + true, expr.get_locus ()); + receiver_ref = indirect; + } + translated = ctx->get_backend ()->struct_field_expression (receiver_ref, index, expr.get_locus ()); @@ -606,6 +626,9 @@ public: void visit (HIR::FieldAccessExpr &expr) override { + Bexpression *receiver_ref + = CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx); + // resolve the receiver back to ADT type TyTy::BaseType *receiver = nullptr; if (!ctx->get_tyctx ()->lookup_type ( @@ -615,17 +638,31 @@ public: "unresolved type for receiver"); return; } - rust_assert (receiver->get_kind () == TyTy::TypeKind::ADT); - TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver); - size_t index = 0; - adt->get_field (expr.get_field_name (), &index); + size_t field_index = 0; + if (receiver->get_kind () == TyTy::TypeKind::ADT) + { + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver); + adt->get_field (expr.get_field_name (), &field_index); + } + else if (receiver->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver); + TyTy::BaseType *b = r->get_base (); + rust_assert (b->get_kind () == TyTy::TypeKind::ADT); - Bexpression *struct_ref - = CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b); + adt->get_field (expr.get_field_name (), &field_index); + Btype *adt_tyty = TyTyResolveCompile::compile (ctx, adt); + + Bexpression *indirect + = ctx->get_backend ()->indirect_expression (adt_tyty, receiver_ref, + true, expr.get_locus ()); + receiver_ref = indirect; + } translated - = ctx->get_backend ()->struct_field_expression (struct_ref, index, + = ctx->get_backend ()->struct_field_expression (receiver_ref, field_index, expr.get_locus ()); } diff --git a/gcc/rust/lint/rust-lint-marklive.cc b/gcc/rust/lint/rust-lint-marklive.cc index f383d48..0871291 100644 --- a/gcc/rust/lint/rust-lint-marklive.cc +++ b/gcc/rust/lint/rust-lint-marklive.cc @@ -214,9 +214,22 @@ MarkLive::visit (HIR::FieldAccessExpr &expr) rust_error_at (expr.get_receiver_expr ()->get_locus (), "unresolved type for receiver"); } - bool ok = receiver->get_kind () == TyTy::TypeKind::ADT; - rust_assert (ok); - TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver); + + TyTy::ADTType *adt = nullptr; + if (receiver->get_kind () == TyTy::TypeKind::ADT) + { + adt = static_cast<TyTy::ADTType *> (receiver); + } + else if (receiver->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver); + TyTy::BaseType *b = r->get_base (); + rust_assert (b->get_kind () == TyTy::TypeKind::ADT); + + adt = static_cast<TyTy::ADTType *> (b); + } + + rust_assert (adt != nullptr); // get the field index size_t index = 0; @@ -228,6 +241,7 @@ MarkLive::visit (HIR::FieldAccessExpr &expr) adt->get_name ().c_str (), index); return; } + // get the field hir id HirId field_id = adt->get_field (index)->get_ref (); mark_hir_id (field_id); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2744516..31c8909 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -64,13 +64,20 @@ public: { auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get (), inside_loop); - if (resolved == nullptr) + if (resolved->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (expr.get_tuple_expr ()->get_locus (), "failed to resolve TupleIndexExpr receiver"); return; } + // FIXME does this require autoderef here? + if (resolved->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved); + resolved = r->get_base (); + } + bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT || resolved->get_kind () == TyTy::TypeKind::TUPLE; if (!is_valid_type) @@ -902,6 +909,14 @@ public: auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get (), false); + // FIXME does this require autoderef here? + if (struct_base->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r + = static_cast<TyTy::ReferenceType *> (struct_base); + struct_base = r->get_base (); + } + bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; if (!is_valid_type) { diff --git a/gcc/testsuite/rust/compile/torture/autoderef1.rs b/gcc/testsuite/rust/compile/torture/autoderef1.rs new file mode 100644 index 0000000..0cf070f --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/autoderef1.rs @@ -0,0 +1,15 @@ +struct Foo(i32, bool); +struct Bar { + a: i32, + b: bool, +} + +fn main() { + let a = &Foo(123, false); + let _b: i32 = a.0; + let _c: bool = a.1; + + let a = &Bar { a: 456, b: false }; + let _b: i32 = a.a; + let _c: bool = a.b; +} |