LCOV - code coverage report
Current view: top level - gcc/rust - rust-session-manager.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 73.3 % 105 77
Test Date: 2026-08-22 16:33:35 Functions: 83.3 % 12 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 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              : #include "rust-name-resolution-context.h"
      28              : 
      29              : #include "config.h"
      30              : #include "rust-system.h"
      31              : #include "coretypes.h"
      32              : #include "options.h"
      33              : 
      34              : #include "optional.h"
      35              : 
      36              : namespace Rust {
      37              : // parser forward decl
      38              : template <typename ManagedTokenSource> class Parser;
      39              : class Lexer;
      40              : // crate forward decl
      41              : namespace AST {
      42              : struct Crate;
      43              : }
      44              : // crate forward decl
      45              : namespace HIR {
      46              : class Crate;
      47              : }
      48              : 
      49              : /* Data related to target, most useful for conditional compilation and
      50              :  * whatever. */
      51              : struct TargetOptions
      52              : {
      53              :   /* TODO: maybe make private and access through helpers to allow changes to
      54              :    * impl */
      55              :   std::unordered_map<std::string, std::unordered_set<tl::optional<std::string>>>
      56              :     features;
      57              : 
      58              :   enum class CrateType
      59              :   {
      60              :     BIN = 0,
      61              :     LIB,
      62              :     RLIB,
      63              :     DYLIB,
      64              :     CDYLIB,
      65              :     STATICLIB,
      66              :     PROC_MACRO
      67              :   } crate_type
      68              :     = CrateType::BIN;
      69              : 
      70              : public:
      71           21 :   void set_crate_type (int raw_type)
      72              :   {
      73           21 :     crate_type = static_cast<CrateType> (raw_type);
      74              :   }
      75              : 
      76              :   const CrateType &get_crate_type () const { return crate_type; }
      77              : 
      78              :   // Returns whether a key is defined in the feature set.
      79         2834 :   bool has_key (std::string key) const
      80              :   {
      81         2834 :     auto it = features.find (key);
      82         2834 :     return it != features.end ()
      83          199 :            && it->second.find (tl::nullopt) != it->second.end ();
      84              :   }
      85              : 
      86              :   // Returns whether a key exists with the given value in the feature set.
      87        14636 :   bool has_key_value_pair (std::string key, std::string value) const
      88              :   {
      89        14636 :     auto it = features.find (key);
      90        14636 :     if (it != features.end ())
      91              :       {
      92        14494 :         auto set = it->second;
      93        28988 :         auto it2 = set.find (value);
      94        14494 :         if (it2 != set.end ())
      95         8384 :           return true;
      96        14494 :       }
      97              :     return false;
      98              :   }
      99              : 
     100              :   /* Returns the singular value from the key, or if the key has multiple, an
     101              :    * empty string. */
     102              :   std::string get_singular_value (std::string key) const
     103              :   {
     104              :     auto it = features.find (key);
     105              :     if (it != features.end ())
     106              :       {
     107              :         auto set = it->second;
     108              :         if (set.size () == 1 && set.begin ()->has_value ())
     109              :           return set.begin ()->value ();
     110              :       }
     111              :     return "";
     112              :   }
     113              : 
     114              :   /* Returns all values associated with a key (including none), or an empty
     115              :    * set if no key is found. */
     116              :   std::unordered_set<std::string> get_values_for_key (std::string key) const
     117              :   {
     118              :     std::unordered_set<std::string> ret;
     119              : 
     120              :     auto it = features.find (key);
     121              :     if (it == features.end ())
     122              :       return {};
     123              : 
     124              :     for (auto &val : it->second)
     125              :       if (val.has_value ())
     126              :         ret.insert (val.value ());
     127              : 
     128              :     return ret;
     129              :   }
     130              : 
     131              :   /* Inserts a key (no value) into the feature set. This will do nothing if
     132              :    * the key already exists. This returns whether the insertion was successful
     133              :    * (i.e. whether key already existed). */
     134           66 :   bool insert_key (std::string key)
     135              :   {
     136           66 :     auto it = features.find (key);
     137              : 
     138           66 :     if (it == features.end ())
     139           66 :       it
     140           66 :         = features
     141           66 :             .insert (
     142          132 :               std::make_pair (std::move (key),
     143          132 :                               std::unordered_set<tl::optional<std::string>> ()))
     144              :             .first;
     145              : 
     146           66 :     return it->second.insert (tl::nullopt).second;
     147              :   }
     148              : 
     149              :   // Inserts a key-value pair into the feature set.
     150        54829 :   void insert_key_value_pair (std::string key, std::string value)
     151              :   {
     152        54829 :     auto it = features.find (key);
     153              : 
     154        54829 :     if (it == features.end ())
     155        39880 :       it
     156        39880 :         = features
     157        39880 :             .insert (
     158        79760 :               std::make_pair (std::move (key),
     159        79760 :                               std::unordered_set<tl::optional<std::string>> ()))
     160              :             .first;
     161              : 
     162        54829 :     it->second.insert (std::move (value));
     163        54829 :   }
     164              : 
     165              :   // Dump all target options to stderr.
     166              :   void dump_target_options () const;
     167              : 
     168              :   /* Creates derived values and implicit enables after all target info is
     169              :    * added (e.g. "unix"). */
     170              :   void init_derived_values ();
     171              : 
     172              :   /* Enables all requirements for the feature given, and will enable feature
     173              :    * itself if not enabled. */
     174              :   void enable_implicit_feature_reqs (std::string feature);
     175              : 
     176              :   /* According to reference, Rust uses either multi-map key-values or just
     177              :    * values (although values may be aliases for a key-value value). This seems
     178              :    * like overkill. Thus, depending on whether the attributes used in cfg are
     179              :    * fixed or not, I think I'll either put each non-multimap "key-value" as a
     180              :    * separate field and have the multimap "key-values" in a regular map for
     181              :    * that one key, or actually use a multimap.
     182              :    *
     183              :    * rustc itself uses a set of key-value tuples where the second tuple
     184              :    * element is optional. This gets rid of the requirement to make a
     185              :    * multi-map, I guess, but seems like it might make search slow (unless all
     186              :    * "is defined"-only ones have empty string as second element). */
     187              :   /* cfg attributes:
     188              :    * - target_arch: single value
     189              :    * - target_feature: multiple values possible
     190              :    * - target_os: single value
     191              :    * - target_family: single value (or no value?)
     192              :    * - unix: set when target_family = "unix"
     193              :    * - windows: set when target_family = "windows"
     194              :    *  - if these are just syntactic sugar, then maybe have a separate set or
     195              :    * map for this kind of stuff
     196              :    * - target_env: set when needed for disambiguation about ABI - usually
     197              :    * empty string for GNU, complicated
     198              :    *  - seems to be a single value (if any)
     199              :    * - target_endian: single value; "little" or "big"
     200              :    * - target_pointer_width: single value, "32" for 32-bit pointers, etc.
     201              :    * - target_vendor, single value
     202              :    * - test: set when testing is being done
     203              :    *  - again, seems similar to a "is defined" rather than "is equal to" like
     204              :    * unix
     205              :    * - debug_assertions: seems to "is defined"
     206              :    * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is
     207              :    * defined"
     208              :    */
     209              : };
     210              : 
     211              : // Defines compiler options (e.g. dump, etc.).
     212              : struct CompileOptions
     213              : {
     214              :   enum DumpOption
     215              :   {
     216              :     LEXER_DUMP,
     217              :     AST_DUMP_PRETTY,
     218              :     REGISTER_PLUGINS_DUMP,
     219              :     INJECTION_DUMP,
     220              :     EXPANSION_DUMP,
     221              :     RESOLUTION_DUMP,
     222              :     TARGET_OPTION_DUMP,
     223              :     HIR_DUMP,
     224              :     HIR_DUMP_PRETTY,
     225              :     BIR_DUMP,
     226              :     INTERNAL_DUMP,
     227              :   };
     228              : 
     229              :   std::set<DumpOption> dump_options;
     230              : 
     231              :   /* List of node that is not print during the dump of the ast with internal
     232              :    * comment */
     233              :   std::set<std::string> excluded_node;
     234              : 
     235              :   /* configuration options - actually useful for conditional compilation and
     236              :    * whatever data related to target arch, features, os, family, env, endian,
     237              :    * pointer width, vendor */
     238              :   TargetOptions target_data;
     239              :   std::string crate_name;
     240              :   bool crate_name_set_manually = false;
     241              :   bool enable_test = false;
     242              :   bool debug_assertions = false;
     243              :   std::string metadata_output_path;
     244              : 
     245              :   int compat_version = 49;
     246              : 
     247              :   /** Structure containing additional attributes to be injected within the
     248              :    * compiled crate from the command line instead of the source code.
     249              :    *
     250              :    * To make things a bit easier with rustc, we're trying to use the same
     251              :    * format accepted by -Zcrate-attr. This means the CLI accepts the text
     252              :    * content of the attribute and not text of the whole attribute itself.
     253              :    */
     254            3 :   struct CliAttributeContent
     255              :   {
     256            1 :     CliAttributeContent (std::string content, location_t locus)
     257            2 :       : content (content), locus (locus)
     258              :     {}
     259              :     /* Content of the attribute*/
     260              :     std::string content;
     261              :     location_t locus;
     262              :   };
     263              :   std::vector<CliAttributeContent> addional_attributes;
     264              : 
     265              :   enum class Edition
     266              :   {
     267              :     E2015 = 0,
     268              :     E2018,
     269              :     E2021,
     270              :   } edition
     271              :     = Edition::E2015;
     272              : 
     273              :   enum class CompileStep
     274              :   {
     275              :     Ast,
     276              :     AttributeCheck,
     277              :     Expansion,
     278              :     ASTValidation,
     279              :     FeatureGating,
     280              :     NameResolution,
     281              :     Lowering,
     282              :     TypeCheck,
     283              :     Privacy,
     284              :     Unsafety,
     285              :     Const,
     286              :     BorrowCheck,
     287              :     Compilation,
     288              :     End,
     289              :   } compile_until
     290              :     = CompileStep::End;
     291              : 
     292              :   enum class PanicStrategy
     293              :   {
     294              :     Unwind,
     295              :     Abort,
     296              :   } panic_strategy
     297              :     = PanicStrategy::Unwind;
     298              : 
     299        48318 :   bool dump_option_enabled (DumpOption option) const
     300              :   {
     301        38834 :     return dump_options.find (option) != dump_options.end ();
     302              :   }
     303              : 
     304            1 :   void enable_dump_option (DumpOption option) { dump_options.insert (option); }
     305              : 
     306            0 :   void enable_all_dump_options ()
     307              :   {
     308            0 :     enable_dump_option (DumpOption::LEXER_DUMP);
     309            0 :     enable_dump_option (DumpOption::AST_DUMP_PRETTY);
     310            0 :     enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP);
     311            0 :     enable_dump_option (DumpOption::INJECTION_DUMP);
     312            0 :     enable_dump_option (DumpOption::EXPANSION_DUMP);
     313            0 :     enable_dump_option (DumpOption::RESOLUTION_DUMP);
     314            0 :     enable_dump_option (DumpOption::TARGET_OPTION_DUMP);
     315            0 :     enable_dump_option (DumpOption::HIR_DUMP);
     316            0 :     enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
     317            0 :     enable_dump_option (DumpOption::BIR_DUMP);
     318            0 :     enable_dump_option (DumpOption::INTERNAL_DUMP);
     319            0 :   }
     320              : 
     321            0 :   void add_excluded (std::string node)
     322              :   {
     323            0 :     rust_assert (!node.empty ());
     324            0 :     excluded_node.insert (node);
     325            0 :   }
     326              : 
     327            0 :   const std::set<std::string> get_excluded () const { return excluded_node; }
     328              : 
     329         4983 :   void set_crate_name (std::string name)
     330              :   {
     331         4983 :     rust_assert (!name.empty ());
     332              : 
     333         4983 :     crate_name = std::move (name);
     334         4983 :   }
     335              : 
     336         9832 :   const std::string &get_crate_name () const
     337              :   {
     338         9832 :     rust_assert (!crate_name.empty ());
     339         9832 :     return crate_name;
     340              :   }
     341              : 
     342           11 :   void set_edition (int raw_edition)
     343              :   {
     344           11 :     edition = static_cast<Edition> (raw_edition);
     345              :   }
     346              : 
     347              :   const Edition &get_edition () const { return edition; }
     348              : 
     349           40 :   void set_compat_version (const char *version)
     350              :   {
     351           40 :     if (!strcmp (version, "max"))
     352              :       {
     353            0 :         compat_version = INT_MAX;
     354            0 :         return;
     355              :       }
     356              : 
     357           40 :     long res;
     358           40 :     char *end_ptr;
     359           40 :     if (version[0] != '1' || version[1] != '.' || version[2] == '\0'
     360           40 :         || (res = strtol (version + 2, &end_ptr, 10), *end_ptr) || res < 0
     361           80 :         || res > INT_MAX)
     362              :       {
     363            0 :         rust_error_at (UNKNOWN_LOCATION,
     364              :                        "compat version must be of form 1.x or be \"max\"");
     365            0 :         return;
     366              :       }
     367              : 
     368           40 :     compat_version = res;
     369              :   }
     370              : 
     371       302155 :   int get_compat_version () const { return compat_version; }
     372              : 
     373           21 :   void set_crate_type (int raw_type) { target_data.set_crate_type (raw_type); }
     374              : 
     375        18188 :   bool is_proc_macro () const
     376              :   {
     377        18188 :     return target_data.get_crate_type ()
     378              :            == TargetOptions::CrateType::PROC_MACRO;
     379              :   }
     380              : 
     381           49 :   void set_compile_step (int raw_step)
     382              :   {
     383           49 :     compile_until = static_cast<CompileStep> (raw_step);
     384              :   }
     385              : 
     386              :   const CompileStep &get_compile_until () const { return compile_until; }
     387              : 
     388            0 :   void set_panic_strategy (int strategy)
     389              :   {
     390            0 :     panic_strategy = static_cast<PanicStrategy> (strategy);
     391              :   }
     392              : 
     393              :   const PanicStrategy &get_panic_strategy () const { return panic_strategy; }
     394              : 
     395            0 :   void set_metadata_output (const std::string &path)
     396              :   {
     397            0 :     metadata_output_path = path;
     398              :   }
     399              : 
     400            0 :   const std::string &get_metadata_output () const
     401              :   {
     402            0 :     return metadata_output_path;
     403              :   }
     404              : 
     405         4305 :   bool metadata_output_path_set () const
     406              :   {
     407         4305 :     return !metadata_output_path.empty ();
     408              :   }
     409              : };
     410              : 
     411              : /* Defines a compiler session. This is for a single compiler invocation, so
     412              :  * potentially includes parsing multiple crates. */
     413              : struct Session
     414              : {
     415              :   CompileOptions options;
     416              :   /* This should really be in a per-crate storage area but it is wiped with
     417              :    * every file so eh. */
     418              :   std::string injected_crate_name;
     419              :   std::map<std::string, std::string> extern_crates;
     420              : 
     421              :   /* extra files get included during late stages of compilation (e.g. macro
     422              :    * expansion) */
     423              :   std::vector<std::string> extra_files;
     424              : 
     425              :   // backend linemap
     426              :   Linemap *linemap;
     427              : 
     428              :   // mappings
     429              :   Analysis::Mappings &mappings;
     430              : 
     431              : public:
     432              :   /* Get a reference to the static session instance */
     433              :   static Session &get_instance ();
     434              : 
     435         4984 :   ~Session () = default;
     436              : 
     437              :   /* This initializes the compiler session. Corresponds to langhook
     438              :    * grs_langhook_init(). Note that this is called after option handling. */
     439              :   void init ();
     440              : 
     441              :   // delete those constructors so we don't access the singleton in any
     442              :   // other way than via `get_instance()`
     443              :   Session (Session const &) = delete;
     444              :   void operator= (Session const &) = delete;
     445              : 
     446              :   bool handle_option (enum opt_code code, const char *arg, HOST_WIDE_INT value,
     447              :                       int kind, location_t loc,
     448              :                       const struct cl_option_handlers *handlers);
     449              :   void handle_input_files (int num_files, const char **files);
     450              :   void init_options ();
     451              :   void handle_crate_name (const char *filename, const AST::Crate &parsed_crate);
     452              : 
     453              :   /* This function saves the filename data into the session manager using the
     454              :    * `move` semantics, and returns a C-style string referencing the input
     455              :    * std::string */
     456            5 :   inline const char *include_extra_file (std::string filename)
     457              :   {
     458            5 :     extra_files.push_back (std::move (filename));
     459            5 :     return extra_files.back ().c_str ();
     460              :   }
     461              : 
     462           72 :   struct LoadedCrate
     463              :   {
     464           24 :     LoadedCrate (std::string name, NodeId node_id,
     465              :                  Resolver2_0::NameResolutionContext ctx)
     466           24 :       : name (std::move (name)), node_id (node_id), ctx (std::move (ctx))
     467              :     {}
     468              : 
     469              :     LoadedCrate (const LoadedCrate &) = delete;
     470              :     LoadedCrate &operator= (const LoadedCrate &) = delete;
     471           48 :     LoadedCrate (LoadedCrate &&other) = default;
     472              : 
     473              :     std::string name;
     474              :     NodeId node_id;
     475              :     Resolver2_0::NameResolutionContext ctx;
     476              :   };
     477              : 
     478              :   struct LoadingError
     479              :   {
     480              :   public:
     481              :     enum class Kind
     482              :     {
     483              :       ALREADY_LOADED,
     484              :       FAILED_TO_LOCATE,
     485              :       COLLISION,
     486              :     } kind;
     487              : 
     488              :     static LoadingError make_already_loaded (NodeId node_id)
     489              :     {
     490              :       return LoadingError{Kind::ALREADY_LOADED, node_id};
     491              :     }
     492              : 
     493              :     static LoadingError make_failed_to_locate ()
     494              :     {
     495              :       return LoadingError{Kind::FAILED_TO_LOCATE, UNKNOWN_NODEID};
     496              :     }
     497              : 
     498              :     static LoadingError make_collision ()
     499              :     {
     500              :       return LoadingError{Kind::COLLISION, UNKNOWN_NODEID};
     501              :     }
     502              :     NodeId node_id;
     503              :   };
     504              : 
     505              :   tl::expected<LoadedCrate, LoadingError>
     506              :   load_extern_crate (const std::string &crate_name, location_t locus);
     507              : 
     508       302155 :   int get_compat_version () const { return options.get_compat_version (); }
     509              : 
     510       148664 :   bool should_support_offset_of () const { return get_compat_version () >= 71; }
     511              : 
     512       148646 :   bool should_support_cfg_select () const
     513              :   {
     514       148646 :     return get_compat_version () >= 90;
     515              :   }
     516              : 
     517              : private:
     518         4984 :   Session () : mappings (Analysis::Mappings::get ()) {}
     519              :   void compile_crate (const char *filename);
     520              :   bool enable_dump (std::string arg);
     521              : 
     522              :   void dump_lex (Parser<Lexer> &parser) const;
     523              :   void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const;
     524              :   void dump_ast_pretty_internal (AST::Crate &crate) const;
     525              :   void dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const;
     526              :   void dump_hir (HIR::Crate &crate) const;
     527              :   void dump_hir_pretty (HIR::Crate &crate) const;
     528              : 
     529              :   void handle_excluded_node (std::string arg);
     530              : 
     531              :   // pipeline stages - TODO maybe move?
     532              :   /* Register plugins pipeline stage. TODO maybe move to another object?
     533              :    * Currently dummy stage. In future will handle attribute injection
     534              :    * (top-level inner attribute creation from command line arguments), setting
     535              :    * options maybe, registering lints maybe, loading plugins maybe. */
     536              :   void register_plugins (AST::Crate &crate);
     537              : 
     538              :   /* Injection pipeline stage. TODO maybe move to another object? Maybe have
     539              :    * some lint checks (in future, obviously), register builtin macros, crate
     540              :    * injection. */
     541              :   void injection (AST::Crate &crate, AST::AttrVec cli_attributes);
     542              : 
     543              :   /* Expansion pipeline stage. TODO maybe move to another object? Expands all
     544              :    * macros, maybe build test harness in future, AST validation, maybe create
     545              :    * macro crate (if not rustdoc).*/
     546              :   void expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx);
     547              : 
     548              :   // handle cfg_option
     549              :   bool handle_cfg_option (std::string &data);
     550              : 
     551              :   bool handle_extern_option (std::string &data);
     552              : };
     553              : 
     554              : } // namespace Rust
     555              : 
     556              : #if CHECKING_P
     557              : namespace selftest {
     558              : extern void rust_crate_name_validation_test (void);
     559              : }
     560              : #endif // CHECKING_P
     561              : 
     562              : #endif
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.