(root)/
gcc-13.2.0/
gcc/
rust/
rust-session-manager.h
       1  // Copyright (C) 2020-2023 Free Software Foundation, Inc.
       2  
       3  // This file is part of GCC.
       4  
       5  // GCC is free software; you can redistribute it and/or modify it under
       6  // the terms of the GNU General Public License as published by the Free
       7  // Software Foundation; either version 3, or (at your option) any later
       8  // version.
       9  
      10  // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11  // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13  // for more details.
      14  
      15  // You should have received a copy of the GNU General Public License
      16  // along with GCC; see the file COPYING3.  If not see
      17  // <http://www.gnu.org/licenses/>.
      18  // #include "rust-session-manager.h"
      19  
      20  #ifndef RUST_SESSION_MANAGER_H
      21  #define RUST_SESSION_MANAGER_H
      22  
      23  #include "rust-linemap.h"
      24  #include "rust-backend.h"
      25  #include "rust-hir-map.h"
      26  #include "safe-ctype.h"
      27  
      28  #include "config.h"
      29  #include "rust-system.h"
      30  #include "coretypes.h"
      31  #include "options.h"
      32  
      33  namespace Rust {
      34  // parser forward decl
      35  template <typename ManagedTokenSource> class Parser;
      36  class Lexer;
      37  // crate forward decl
      38  namespace AST {
      39  struct Crate;
      40  }
      41  // crate forward decl
      42  namespace HIR {
      43  struct Crate;
      44  }
      45  
      46  /* Data related to target, most useful for conditional compilation and
      47   * whatever. */
      48  struct TargetOptions
      49  {
      50    /* TODO: maybe make private and access through helpers to allow changes to
      51     * impl */
      52    std::unordered_map<std::string, std::unordered_set<std::string> > features;
      53  
      54  public:
      55    // Returns whether a key is defined in the feature set.
      56    bool has_key (std::string key) const
      57    {
      58      return features.find (key) != features.end ();
      59    }
      60  
      61    // Returns whether a key exists with the given value in the feature set.
      62    bool has_key_value_pair (std::string key, std::string value) const
      63    {
      64      auto it = features.find (key);
      65      if (it != features.end ())
      66        {
      67  	auto set = it->second;
      68  	auto it2 = set.find (value);
      69  	if (it2 != set.end ())
      70  	  return true;
      71        }
      72      return false;
      73    }
      74  
      75    /* Returns the singular value from the key, or if the key has multiple, an
      76     * empty string. */
      77    std::string get_singular_value (std::string key) const
      78    {
      79      auto it = features.find (key);
      80      if (it != features.end ())
      81        {
      82  	auto set = it->second;
      83  	if (set.size () == 1)
      84  	  return *set.begin ();
      85        }
      86      return "";
      87    }
      88  
      89    /* Returns all values associated with a key (including none), or an empty
      90     * set if no key is found. */
      91    std::unordered_set<std::string> get_values_for_key (std::string key) const
      92    {
      93      auto it = features.find (key);
      94      if (it != features.end ())
      95        return it->second;
      96      return {};
      97    }
      98  
      99    /* Inserts a key (no value) into the feature set. This will do nothing if
     100     * the key already exists. This returns whether the insertion was successful
     101     * (i.e. whether key already existed). */
     102    bool insert_key (std::string key)
     103    {
     104      return features
     105        .insert (std::make_pair (key, std::unordered_set<std::string> ()))
     106        .second;
     107    }
     108  
     109    // Inserts a key-value pair into the feature set.
     110    void insert_key_value_pair (std::string key, std::string value)
     111    {
     112      auto existing_set = get_values_for_key (key);
     113      existing_set.insert (std::move (value));
     114      features[std::move (key)] = std::move (existing_set);
     115    }
     116  
     117    // Dump all target options to stderr.
     118    void dump_target_options () const;
     119  
     120    /* Creates derived values and implicit enables after all target info is
     121     * added (e.g. "unix"). */
     122    void init_derived_values ();
     123  
     124    /* Enables all requirements for the feature given, and will enable feature
     125     * itself if not enabled. */
     126    void enable_implicit_feature_reqs (std::string feature);
     127  
     128    /* According to reference, Rust uses either multi-map key-values or just
     129     * values (although values may be aliases for a key-value value). This seems
     130     * like overkill. Thus, depending on whether the attributes used in cfg are
     131     * fixed or not, I think I'll either put each non-multimap "key-value" as a
     132     * separate field and have the multimap "key-values" in a regular map for
     133     * that one key, or actually use a multimap.
     134     *
     135     * rustc itself uses a set of key-value tuples where the second tuple
     136     * element is optional. This gets rid of the requirement to make a
     137     * multi-map, I guess, but seems like it might make search slow (unless all
     138     * "is defined"-only ones have empty string as second element). */
     139    /* cfg attributes:
     140     * - target_arch: single value
     141     * - target_feature: multiple values possible
     142     * - target_os: single value
     143     * - target_family: single value (or no value?)
     144     * - unix: set when target_family = "unix"
     145     * - windows: set when target_family = "windows"
     146     *  - if these are just syntactic sugar, then maybe have a separate set or
     147     * map for this kind of stuff
     148     * - target_env: set when needed for disambiguation about ABI - usually
     149     * empty string for GNU, complicated
     150     *  - seems to be a single value (if any)
     151     * - target_endian: single value; "little" or "big"
     152     * - target_pointer_width: single value, "32" for 32-bit pointers, etc.
     153     * - target_vendor, single value
     154     * - test: set when testing is being done
     155     *  - again, seems similar to a "is defined" rather than "is equal to" like
     156     * unix
     157     * - debug_assertions: seems to "is defined"
     158     * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is
     159     * defined"
     160     */
     161  };
     162  
     163  // Defines compiler options (e.g. dump, etc.).
     164  struct CompileOptions
     165  {
     166    enum DumpOption
     167    {
     168      LEXER_DUMP,
     169      PARSER_AST_DUMP,
     170      AST_DUMP_PRETTY,
     171      REGISTER_PLUGINS_DUMP,
     172      INJECTION_DUMP,
     173      EXPANSION_DUMP,
     174      RESOLUTION_DUMP,
     175      TARGET_OPTION_DUMP,
     176      HIR_DUMP,
     177      HIR_DUMP_PRETTY,
     178      TYPE_RESOLUTION_DUMP,
     179    };
     180  
     181    std::set<DumpOption> dump_options;
     182  
     183    /* configuration options - actually useful for conditional compilation and
     184     * whatever data related to target arch, features, os, family, env, endian,
     185     * pointer width, vendor */
     186    TargetOptions target_data;
     187    std::string crate_name;
     188    bool crate_name_set_manually = false;
     189    bool enable_test = false;
     190    bool debug_assertions = false;
     191    bool proc_macro = false;
     192    std::string metadata_output_path;
     193  
     194    enum class Edition
     195    {
     196      E2015 = 0,
     197      E2018,
     198      E2021,
     199    } edition
     200      = Edition::E2015;
     201  
     202    enum class CompileStep
     203    {
     204      Ast,
     205      AttributeCheck,
     206      Expansion,
     207      NameResolution,
     208      Lowering,
     209      TypeCheck,
     210      Privacy,
     211      Unsafety,
     212      Const,
     213      Compilation,
     214      End,
     215    } compile_until
     216      = CompileStep::End;
     217  
     218    bool dump_option_enabled (DumpOption option) const
     219    {
     220      return dump_options.find (option) != dump_options.end ();
     221    }
     222  
     223    void enable_dump_option (DumpOption option) { dump_options.insert (option); }
     224  
     225    void enable_all_dump_options ()
     226    {
     227      enable_dump_option (DumpOption::LEXER_DUMP);
     228      enable_dump_option (DumpOption::PARSER_AST_DUMP);
     229      enable_dump_option (DumpOption::AST_DUMP_PRETTY);
     230      enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP);
     231      enable_dump_option (DumpOption::INJECTION_DUMP);
     232      enable_dump_option (DumpOption::EXPANSION_DUMP);
     233      enable_dump_option (DumpOption::RESOLUTION_DUMP);
     234      enable_dump_option (DumpOption::TARGET_OPTION_DUMP);
     235      enable_dump_option (DumpOption::HIR_DUMP);
     236      enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
     237      enable_dump_option (DumpOption::TYPE_RESOLUTION_DUMP);
     238    }
     239  
     240    void set_crate_name (std::string name)
     241    {
     242      rust_assert (!name.empty ());
     243  
     244      crate_name = std::move (name);
     245    }
     246  
     247    const std::string &get_crate_name () const
     248    {
     249      rust_assert (!crate_name.empty ());
     250      return crate_name;
     251    }
     252  
     253    void set_edition (int raw_edition)
     254    {
     255      edition = static_cast<Edition> (raw_edition);
     256    }
     257  
     258    const Edition &get_edition () const { return edition; }
     259  
     260    void set_compile_step (int raw_step)
     261    {
     262      compile_until = static_cast<CompileStep> (raw_step);
     263    }
     264  
     265    const CompileStep &get_compile_until () const { return compile_until; }
     266  
     267    void set_metadata_output (const std::string &path)
     268    {
     269      metadata_output_path = path;
     270    }
     271  
     272    const std::string &get_metadata_output () const
     273    {
     274      return metadata_output_path;
     275    }
     276  
     277    bool metadata_output_path_set () const
     278    {
     279      return !metadata_output_path.empty ();
     280    }
     281  };
     282  
     283  /* Defines a compiler session. This is for a single compiler invocation, so
     284   * potentially includes parsing multiple crates. */
     285  struct Session
     286  {
     287    CompileOptions options;
     288    /* This should really be in a per-crate storage area but it is wiped with
     289     * every file so eh. */
     290    std::string injected_crate_name;
     291  
     292    /* extra files get included during late stages of compilation (e.g. macro
     293     * expansion) */
     294    std::vector<std::string> extra_files;
     295  
     296    // backend wrapper to GCC GENERIC
     297    Backend *backend;
     298  
     299    // backend linemap
     300    Linemap *linemap;
     301  
     302    // mappings
     303    Analysis::Mappings *mappings;
     304  
     305  public:
     306    /* Get a reference to the static session instance */
     307    static Session &get_instance ();
     308  
     309    Session () = default;
     310    ~Session () = default;
     311  
     312    /* This initializes the compiler session. Corresponds to langhook
     313     * grs_langhook_init(). Note that this is called after option handling. */
     314    void init ();
     315  
     316    // delete those constructors so we don't access the singleton in any
     317    // other way than via `get_instance()`
     318    Session (Session const &) = delete;
     319    void operator= (Session const &) = delete;
     320  
     321    bool handle_option (enum opt_code code, const char *arg, HOST_WIDE_INT value,
     322  		      int kind, location_t loc,
     323  		      const struct cl_option_handlers *handlers);
     324    void handle_input_files (int num_files, const char **files);
     325    void init_options ();
     326    void handle_crate_name (const AST::Crate &parsed_crate);
     327  
     328    /* This function saves the filename data into the session manager using the
     329     * `move` semantics, and returns a C-style string referencing the input
     330     * std::string */
     331    inline const char *include_extra_file (std::string filename)
     332    {
     333      extra_files.push_back (std::move (filename));
     334      return extra_files.back ().c_str ();
     335    }
     336  
     337    NodeId load_extern_crate (const std::string &crate_name, Location locus);
     338  
     339  private:
     340    void compile_crate (const char *filename);
     341    bool enable_dump (std::string arg);
     342  
     343    void dump_lex (Parser<Lexer> &parser) const;
     344    void dump_ast (Parser<Lexer> &parser, AST::Crate &crate) const;
     345    void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const;
     346    void dump_ast_expanded (Parser<Lexer> &parser, AST::Crate &crate) const;
     347    void dump_hir (HIR::Crate &crate) const;
     348    void dump_hir_pretty (HIR::Crate &crate) const;
     349    void dump_type_resolution (HIR::Crate &crate) const;
     350  
     351    // pipeline stages - TODO maybe move?
     352    /* Register plugins pipeline stage. TODO maybe move to another object?
     353     * Currently dummy stage. In future will handle attribute injection
     354     * (top-level inner attribute creation from command line arguments), setting
     355     * options maybe, registering lints maybe, loading plugins maybe. */
     356    void register_plugins (AST::Crate &crate);
     357  
     358    /* Injection pipeline stage. TODO maybe move to another object? Maybe have
     359     * some lint checks (in future, obviously), register builtin macros, crate
     360     * injection. */
     361    void injection (AST::Crate &crate);
     362  
     363    /* Expansion pipeline stage. TODO maybe move to another object? Expands all
     364     * macros, maybe build test harness in future, AST validation, maybe create
     365     * macro crate (if not rustdoc).*/
     366    void expansion (AST::Crate &crate);
     367  
     368    // handle cfg_option
     369    bool handle_cfg_option (std::string &data);
     370  };
     371  
     372  } // namespace Rust
     373  
     374  #if CHECKING_P
     375  namespace selftest {
     376  extern void
     377  rust_crate_name_validation_test (void);
     378  }
     379  #endif // CHECKING_P
     380  
     381  #endif