diff options
-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 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/closure3.rs | 33 |
6 files changed, 172 insertions, 6 deletions
diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index b989741..018897e 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 d2d3a53..8e8fac8 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 8169ba0..436fc92 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -2829,10 +2829,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, @@ -2879,8 +2894,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 @@ -2910,7 +2946,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 (); @@ -2977,6 +3016,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 ab8e628..8857df2 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 824cb3a..c8e1d3b 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); } diff --git a/gcc/testsuite/rust/execute/torture/closure3.rs b/gcc/testsuite/rust/execute/torture/closure3.rs new file mode 100644 index 0000000..62cf3a0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/closure3.rs @@ -0,0 +1,33 @@ +// { dg-output "3\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +fn f<F: FnOnce(i32) -> i32>(g: F) { + let call = g(1); + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, call); + } +} + +pub fn main() -> i32 { + let capture = 2; + let a = |i: i32| { + let b = i + capture; + b + }; + f(a); + 0 +} |