// Copyright (C) 2020-2024 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #ifndef RUST_COMPILE_CONTEXT #define RUST_COMPILE_CONTEXT #include "rust-system.h" #include "rust-hir-map.h" #include "rust-name-resolver.h" #include "rust-hir-type-check.h" #include "rust-backend.h" #include "rust-hir-full.h" #include "rust-mangle.h" #include "rust-tree.h" #include "rust-immutable-name-resolution-context.h" namespace Rust { namespace Compile { struct fncontext { tree fndecl; ::Bvariable *ret_addr; TyTy::BaseType *retty; }; struct CustomDeriveInfo { tree fndecl; std::string trait_name; std::vector attributes; }; class Context { public: Context (); void setup_builtins (); bool lookup_compiled_types (tree t, tree *type) { hashval_t h = type_hasher (t); auto it = compiled_type_map.find (h); if (it == compiled_type_map.end ()) return false; *type = it->second; return true; } tree insert_compiled_type (tree type) { hashval_t h = type_hasher (type); auto it = compiled_type_map.find (h); if (it != compiled_type_map.end ()) return it->second; compiled_type_map.insert ({h, type}); push_type (type); return type; } tree insert_main_variant (tree type) { hashval_t h = type_hasher (type); auto it = main_variants.find (h); if (it != main_variants.end ()) return it->second; main_variants.insert ({h, type}); return type; } Resolver::Resolver *get_resolver () { return resolver; } Resolver::TypeCheckContext *get_tyctx () { return tyctx; } Analysis::Mappings *get_mappings () { return mappings; } void push_block (tree scope) { scope_stack.push_back (scope); statements.push_back ({}); } tree pop_block () { auto block = scope_stack.back (); scope_stack.pop_back (); auto stmts = statements.back (); statements.pop_back (); Backend::block_add_statements (block, stmts); return block; } tree peek_enclosing_scope () { if (scope_stack.size () == 0) return nullptr; return scope_stack.back (); } void add_statement_to_enclosing_scope (tree stmt) { statements.at (statements.size () - 2).push_back (stmt); } void add_statement (tree stmt) { statements.back ().push_back (stmt); } void insert_var_decl (HirId id, ::Bvariable *decl) { compiled_var_decls[id] = decl; } bool lookup_var_decl (HirId id, ::Bvariable **decl) { auto it = compiled_var_decls.find (id); if (it == compiled_var_decls.end ()) return false; *decl = it->second; return true; } void insert_function_decl (const TyTy::FnType *ref, tree fn) { auto id = ref->get_ty_ref (); auto dId = ref->get_id (); rust_assert (compiled_fn_map.find (id) == compiled_fn_map.end ()); compiled_fn_map[id] = fn; auto it = mono_fns.find (dId); if (it == mono_fns.end ()) mono_fns[dId] = {}; mono_fns[dId].push_back ({ref, fn}); } void insert_closure_decl (const TyTy::ClosureType *ref, tree fn) { auto dId = ref->get_def_id (); auto it = mono_closure_fns.find (dId); if (it == mono_closure_fns.end ()) mono_closure_fns[dId] = {}; mono_closure_fns[dId].push_back ({ref, fn}); } tree lookup_closure_decl (const TyTy::ClosureType *ref) { auto dId = ref->get_def_id (); auto it = mono_closure_fns.find (dId); if (it == mono_closure_fns.end ()) return error_mark_node; for (auto &i : it->second) { const TyTy::ClosureType *t = i.first; tree fn = i.second; if (ref->is_equal (*t)) return fn; } return error_mark_node; } bool lookup_function_decl (HirId id, tree *fn, DefId dId = UNKNOWN_DEFID, const TyTy::BaseType *ref = nullptr, const std::string &asm_name = std::string ()) { // for for any monomorphized fns if (ref != nullptr) { rust_assert (dId != UNKNOWN_DEFID); auto it = mono_fns.find (dId); if (it == mono_fns.end ()) return false; for (auto &e : mono_fns[dId]) { const TyTy::BaseType *r = e.first; tree f = e.second; if (ref->is_equal (*r)) { *fn = f; return true; } if (DECL_ASSEMBLER_NAME_SET_P (f) && !asm_name.empty ()) { tree raw = DECL_ASSEMBLER_NAME_RAW (f); const char *rptr = IDENTIFIER_POINTER (raw); bool lengths_match_p = IDENTIFIER_LENGTH (raw) == asm_name.size (); if (lengths_match_p && strncmp (rptr, asm_name.c_str (), IDENTIFIER_LENGTH (raw)) == 0) { *fn = f; return true; } } } return false; } auto it = compiled_fn_map.find (id); if (it == compiled_fn_map.end ()) return false; *fn = it->second; return true; } void insert_const_decl (HirId id, tree expr) { compiled_consts[id] = expr; } bool lookup_const_decl (HirId id, tree *expr) { auto it = compiled_consts.find (id); if (it == compiled_consts.end ()) return false; *expr = it->second; return true; } void insert_label_decl (HirId id, tree label) { compiled_labels[id] = label; } bool lookup_label_decl (HirId id, tree *label) { auto it = compiled_labels.find (id); if (it == compiled_labels.end ()) return false; *label = it->second; return true; } void insert_pattern_binding (HirId id, tree binding) { implicit_pattern_bindings[id] = binding; } bool lookup_pattern_binding (HirId id, tree *binding) { auto it = implicit_pattern_bindings.find (id); if (it == implicit_pattern_bindings.end ()) return false; *binding = it->second; return true; } void push_fn (tree fn, ::Bvariable *ret_addr, TyTy::BaseType *retty) { fn_stack.push_back (fncontext{fn, ret_addr, retty}); } void pop_fn () { fn_stack.pop_back (); } bool in_fn () { return fn_stack.size () != 0; } // Note: it is undefined behavior to call peek_fn () if fn_stack is empty. fncontext peek_fn () { rust_assert (!fn_stack.empty ()); return fn_stack.back (); } void push_type (tree t) { type_decls.push_back (t); } void push_var (::Bvariable *v) { var_decls.push_back (v); } void push_const (tree c) { const_decls.push_back (c); } void push_function (tree f) { func_decls.push_back (f); } void write_to_backend () { Backend::write_global_definitions (type_decls, const_decls, func_decls, var_decls); } bool function_completed (tree fn) { for (auto it = func_decls.begin (); it != func_decls.end (); it++) { tree i = (*it); if (i == fn) { return true; } } return false; } void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); } Bvariable *peek_loop_context () { return loop_value_stack.back (); } Bvariable *pop_loop_context () { auto back = loop_value_stack.back (); loop_value_stack.pop_back (); return back; } void push_loop_begin_label (tree label) { loop_begin_labels.push_back (label); } tree peek_loop_begin_label () { return loop_begin_labels.back (); } tree pop_loop_begin_label () { tree pop = loop_begin_labels.back (); loop_begin_labels.pop_back (); return pop; } void push_const_context (void) { const_context++; } void pop_const_context (void) { if (const_context > 0) const_context--; } bool const_context_p (void) { return (const_context > 0); } std::string mangle_item (const TyTy::BaseType *ty, const Resolver::CanonicalPath &path) { return mangler.mangle_item (this, 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 &get_type_decls () { return type_decls; } std::vector<::Bvariable *> &get_var_decls () { return var_decls; } std::vector &get_const_decls () { return const_decls; } std::vector &get_func_decls () { return func_decls; } static hashval_t type_hasher (tree type); void collect_attribute_proc_macro (tree fndecl) { attribute_macros.push_back (fndecl); } void collect_bang_proc_macro (tree fndecl) { bang_macros.push_back (fndecl); } void collect_derive_proc_macro (CustomDeriveInfo macro) { custom_derive_macros.push_back (macro); } const std::vector &get_bang_proc_macros () const { return bang_macros; } const std::vector &get_attribute_proc_macros () const { return attribute_macros; } const std::vector &get_derive_proc_macros () const { return custom_derive_macros; } private: Resolver::Resolver *resolver; Resolver::TypeCheckContext *tyctx; Analysis::Mappings *mappings; Mangler mangler; // state std::vector fn_stack; std::map compiled_var_decls; std::map compiled_type_map; std::map compiled_fn_map; std::map compiled_consts; std::map compiled_labels; std::vector<::std::vector> statements; std::vector scope_stack; std::vector<::Bvariable *> loop_value_stack; std::vector loop_begin_labels; std::map>> mono_fns; std::map>> mono_closure_fns; std::map implicit_pattern_bindings; std::map main_variants; std::vector custom_derive_macros; std::vector attribute_macros; std::vector bang_macros; // closure bindings std::vector closure_scope_bindings; std::map> closure_bindings; // To GCC middle-end std::vector type_decls; std::vector<::Bvariable *> var_decls; std::vector const_decls; std::vector func_decls; // Nonzero iff we are currently compiling something inside a constant context. unsigned int const_context = 0; }; } // namespace Compile } // namespace Rust #endif // RUST_COMPILE_CONTEXT