diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-12-04 22:02:22 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-04 22:02:22 +0000 |
commit | e39fadcd0aa4d52d53667e2adad9a6677f7e9adf (patch) | |
tree | b412e8330dfb14001b7c66483520fe99e029f4d2 /gcc/rust/backend | |
parent | 22329b03a6e0a3381d907745205012cf290b3c2a (diff) | |
parent | 3053ec366093560a6269aaace61ce77fb8710b01 (diff) | |
download | gcc-e39fadcd0aa4d52d53667e2adad9a6677f7e9adf.zip gcc-e39fadcd0aa4d52d53667e2adad9a6677f7e9adf.tar.gz gcc-e39fadcd0aa4d52d53667e2adad9a6677f7e9adf.tar.bz2 |
Merge #1611
1611: Initial state capture for closures r=philberty a=philberty
This patch set adds the initial support closure captures, move semantics are not
handled here. We track what variables are being captured by a closure during
name resolution so that when a VAR_DECL is resolved, we check if we are inside
a closure context node_id which is the same id as its associated rib id. So when
we resolve a name that resides in an outermost rib we can add this to set of
node-id's that are captured by this closure.
There is a gap here for the case where we need to check if it is inside a nested
function and that function contains closures which could wrongly capture variables
in the enclosing function. This will also be a problem for nested functions in general.
Fixes #195
Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc/rust/backend')
-rw-r--r-- | gcc/rust/backend/rust-compile-context.cc | 47 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-context.h | 9 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.cc | 50 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.cc | 8 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-type.cc | 31 |
5 files changed, 139 insertions, 6 deletions
diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index cb2addf6..0687398 100644 --- a/gcc/rust/backend/rust-compile-context.cc +++ b/gcc/rust/backend/rust-compile-context.cc @@ -142,5 +142,52 @@ Context::type_hasher (tree type) return hstate.end (); } +void +Context::push_closure_context (HirId id) +{ + auto it = closure_bindings.find (id); + rust_assert (it == closure_bindings.end ()); + + closure_bindings.insert ({id, {}}); + closure_scope_bindings.push_back (id); +} + +void +Context::pop_closure_context () +{ + rust_assert (!closure_scope_bindings.empty ()); + + HirId ref = closure_scope_bindings.back (); + closure_scope_bindings.pop_back (); + closure_bindings.erase (ref); +} + +void +Context::insert_closure_binding (HirId id, tree expr) +{ + rust_assert (!closure_scope_bindings.empty ()); + + HirId ref = closure_scope_bindings.back (); + closure_bindings[ref].insert ({id, expr}); +} + +bool +Context::lookup_closure_binding (HirId id, tree *expr) +{ + if (closure_scope_bindings.empty ()) + return false; + + HirId ref = closure_scope_bindings.back (); + auto it = closure_bindings.find (ref); + rust_assert (it != closure_bindings.end ()); + + auto iy = it->second.find (id); + if (iy == it->second.end ()) + return false; + + *expr = iy->second; + return true; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 658b9a3..7744f01 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -345,6 +345,11 @@ public: return mangler.mangle_item (ty, path); } + void push_closure_context (HirId id); + void pop_closure_context (); + void insert_closure_binding (HirId id, tree expr); + bool lookup_closure_binding (HirId id, tree *expr); + std::vector<tree> &get_type_decls () { return type_decls; } std::vector<::Bvariable *> &get_var_decls () { return var_decls; } std::vector<tree> &get_const_decls () { return const_decls; } @@ -377,6 +382,10 @@ private: std::map<HirId, tree> implicit_pattern_bindings; std::map<hashval_t, tree> main_variants; + // closure bindings + std::vector<HirId> closure_scope_bindings; + std::map<HirId, std::map<HirId, tree>> closure_bindings; + // To GCC middle-end std::vector<tree> type_decls; std::vector<::Bvariable *> var_decls; diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index b077a12..e50df63 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -2824,10 +2824,25 @@ CompileExpr::visit (HIR::ClosureExpr &expr) // lets ignore state capture for now we need to instantiate the struct anyway // then generate the function - std::vector<tree> vals; - // TODO - // setup argument captures based on the mode? + for (const auto &capture : closure_tyty->get_captures ()) + { + // lookup the HirId + HirId ref = UNKNOWN_HIRID; + bool ok = ctx->get_mappings ()->lookup_node_to_hir (capture, &ref); + rust_assert (ok); + + // lookup the var decl + Bvariable *var = nullptr; + bool found = ctx->lookup_var_decl (ref, &var); + rust_assert (found); + + // FIXME + // this should bes based on the closure move-ability + tree var_expr = var->get_tree (expr.get_locus ()); + tree val = address_expression (var_expr, expr.get_locus ()); + vals.push_back (val); + } translated = ctx->get_backend ()->constructor_expression (compiled_closure_tyty, false, @@ -2874,8 +2889,29 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, DECL_ARTIFICIAL (self_param->get_decl ()) = 1; param_vars.push_back (self_param); + // push a new context + ctx->push_closure_context (expr.get_mappings ().get_hirid ()); + // setup the implicit argument captures - // TODO + size_t idx = 0; + for (const auto &capture : closure_tyty.get_captures ()) + { + // lookup the HirId + HirId ref = UNKNOWN_HIRID; + bool ok = ctx->get_mappings ()->lookup_node_to_hir (capture, &ref); + rust_assert (ok); + + // get the assessor + tree binding = ctx->get_backend ()->struct_field_expression ( + self_param->get_tree (expr.get_locus ()), idx, expr.get_locus ()); + tree indirection = indirect_expression (binding, expr.get_locus ()); + + // insert bindings + ctx->insert_closure_binding (ref, indirection); + + // continue + idx++; + } // args tuple tree args_type @@ -2905,7 +2941,10 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, } if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) - return error_mark_node; + { + ctx->pop_closure_context (); + return error_mark_node; + } // lookup locals HIR::Expr *function_body = expr.get_expr ().get (); @@ -2972,6 +3011,7 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); DECL_SAVED_TREE (fndecl) = bind_tree; + ctx->pop_closure_context (); ctx->pop_fn (); ctx->push_function (fndecl); diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index f89da2b..eaa748a 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -121,6 +121,14 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, return constant_expr; } + // maybe closure binding + tree closure_binding = error_mark_node; + if (ctx->lookup_closure_binding (ref, &closure_binding)) + { + TREE_USED (closure_binding) = 1; + return closure_binding; + } + // this might be a variable reference or a function reference Bvariable *var = nullptr; if (ctx->lookup_var_decl (ref, &var)) diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 5e56e0a..4c72d6f 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -19,6 +19,7 @@ #include "rust-compile-type.h" #include "rust-compile-expr.h" #include "rust-constexpr.h" +#include "rust-gcc.h" #include "tree.h" @@ -99,11 +100,39 @@ TyTyResolveCompile::visit (const TyTy::InferType &) void TyTyResolveCompile::visit (const TyTy::ClosureType &type) { + auto mappings = ctx->get_mappings (); + std::vector<Backend::typed_identifier> fields; + + size_t i = 0; + for (const auto &capture : type.get_captures ()) + { + // lookup the HirId + HirId ref = UNKNOWN_HIRID; + bool ok = mappings->lookup_node_to_hir (capture, &ref); + rust_assert (ok); + + // lookup the var decl type + TyTy::BaseType *lookup = nullptr; + bool found = ctx->get_tyctx ()->lookup_type (ref, &lookup); + rust_assert (found); + + // FIXME get the var pattern name + std::string mappings_name = "capture_" + std::to_string (i); + + // FIXME + // this should be based on the closure move-ability + tree decl_type = TyTyResolveCompile::compile (ctx, lookup); + tree capture_type = build_reference_type (decl_type); + fields.push_back (Backend::typed_identifier (mappings_name, capture_type, + type.get_ident ().locus)); + } + tree type_record = ctx->get_backend ()->struct_type (fields); RS_CLOSURE_FLAG (type_record) = 1; - std::string named_struct_str = type.get_ident ().path.get () + "{{closure}}"; + std::string named_struct_str + = type.get_ident ().path.get () + "::{{closure}}"; translated = ctx->get_backend ()->named_type (named_struct_str, type_record, type.get_ident ().locus); } |