mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
466 lines
13 KiB
C++
466 lines
13 KiB
C++
// Copyright (C) 2020-2026 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
|
|
// <http://www.gnu.org/licenses/>.
|
|
// #include "rust-session-manager.h"
|
|
|
|
#ifndef RUST_SESSION_MANAGER_H
|
|
#define RUST_SESSION_MANAGER_H
|
|
|
|
#include "rust-linemap.h"
|
|
#include "rust-backend.h"
|
|
#include "rust-hir-map.h"
|
|
#include "safe-ctype.h"
|
|
#include "rust-name-resolution-context.h"
|
|
|
|
#include "config.h"
|
|
#include "rust-system.h"
|
|
#include "coretypes.h"
|
|
#include "options.h"
|
|
|
|
#include "optional.h"
|
|
|
|
namespace Rust {
|
|
// parser forward decl
|
|
template <typename ManagedTokenSource> class Parser;
|
|
class Lexer;
|
|
// crate forward decl
|
|
namespace AST {
|
|
struct Crate;
|
|
}
|
|
// crate forward decl
|
|
namespace HIR {
|
|
class Crate;
|
|
}
|
|
|
|
/* Data related to target, most useful for conditional compilation and
|
|
* whatever. */
|
|
struct TargetOptions
|
|
{
|
|
/* TODO: maybe make private and access through helpers to allow changes to
|
|
* impl */
|
|
std::unordered_map<std::string, std::unordered_set<tl::optional<std::string>>>
|
|
features;
|
|
|
|
enum class CrateType
|
|
{
|
|
BIN = 0,
|
|
LIB,
|
|
RLIB,
|
|
DYLIB,
|
|
CDYLIB,
|
|
STATICLIB,
|
|
PROC_MACRO
|
|
} crate_type
|
|
= CrateType::BIN;
|
|
|
|
public:
|
|
void set_crate_type (int raw_type)
|
|
{
|
|
crate_type = static_cast<CrateType> (raw_type);
|
|
}
|
|
|
|
const CrateType &get_crate_type () const { return crate_type; }
|
|
|
|
// Returns whether a key is defined in the feature set.
|
|
bool has_key (std::string key) const
|
|
{
|
|
auto it = features.find (key);
|
|
return it != features.end ()
|
|
&& it->second.find (tl::nullopt) != it->second.end ();
|
|
}
|
|
|
|
// Returns whether a key exists with the given value in the feature set.
|
|
bool has_key_value_pair (std::string key, std::string value) const
|
|
{
|
|
auto it = features.find (key);
|
|
if (it != features.end ())
|
|
{
|
|
auto set = it->second;
|
|
auto it2 = set.find (value);
|
|
if (it2 != set.end ())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Returns the singular value from the key, or if the key has multiple, an
|
|
* empty string. */
|
|
std::string get_singular_value (std::string key) const
|
|
{
|
|
auto it = features.find (key);
|
|
if (it != features.end ())
|
|
{
|
|
auto set = it->second;
|
|
if (set.size () == 1 && set.begin ()->has_value ())
|
|
return set.begin ()->value ();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/* Returns all values associated with a key (including none), or an empty
|
|
* set if no key is found. */
|
|
std::unordered_set<std::string> get_values_for_key (std::string key) const
|
|
{
|
|
std::unordered_set<std::string> ret;
|
|
|
|
auto it = features.find (key);
|
|
if (it == features.end ())
|
|
return {};
|
|
|
|
for (auto &val : it->second)
|
|
if (val.has_value ())
|
|
ret.insert (val.value ());
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Inserts a key (no value) into the feature set. This will do nothing if
|
|
* the key already exists. This returns whether the insertion was successful
|
|
* (i.e. whether key already existed). */
|
|
bool insert_key (std::string key)
|
|
{
|
|
auto it = features.find (key);
|
|
|
|
if (it == features.end ())
|
|
it
|
|
= features
|
|
.insert (
|
|
std::make_pair (std::move (key),
|
|
std::unordered_set<tl::optional<std::string>> ()))
|
|
.first;
|
|
|
|
return it->second.insert (tl::nullopt).second;
|
|
}
|
|
|
|
// Inserts a key-value pair into the feature set.
|
|
void insert_key_value_pair (std::string key, std::string value)
|
|
{
|
|
auto it = features.find (key);
|
|
|
|
if (it == features.end ())
|
|
it
|
|
= features
|
|
.insert (
|
|
std::make_pair (std::move (key),
|
|
std::unordered_set<tl::optional<std::string>> ()))
|
|
.first;
|
|
|
|
it->second.insert (std::move (value));
|
|
}
|
|
|
|
// Dump all target options to stderr.
|
|
void dump_target_options () const;
|
|
|
|
/* Creates derived values and implicit enables after all target info is
|
|
* added (e.g. "unix"). */
|
|
void init_derived_values ();
|
|
|
|
/* Enables all requirements for the feature given, and will enable feature
|
|
* itself if not enabled. */
|
|
void enable_implicit_feature_reqs (std::string feature);
|
|
|
|
/* According to reference, Rust uses either multi-map key-values or just
|
|
* values (although values may be aliases for a key-value value). This seems
|
|
* like overkill. Thus, depending on whether the attributes used in cfg are
|
|
* fixed or not, I think I'll either put each non-multimap "key-value" as a
|
|
* separate field and have the multimap "key-values" in a regular map for
|
|
* that one key, or actually use a multimap.
|
|
*
|
|
* rustc itself uses a set of key-value tuples where the second tuple
|
|
* element is optional. This gets rid of the requirement to make a
|
|
* multi-map, I guess, but seems like it might make search slow (unless all
|
|
* "is defined"-only ones have empty string as second element). */
|
|
/* cfg attributes:
|
|
* - target_arch: single value
|
|
* - target_feature: multiple values possible
|
|
* - target_os: single value
|
|
* - target_family: single value (or no value?)
|
|
* - unix: set when target_family = "unix"
|
|
* - windows: set when target_family = "windows"
|
|
* - if these are just syntactic sugar, then maybe have a separate set or
|
|
* map for this kind of stuff
|
|
* - target_env: set when needed for disambiguation about ABI - usually
|
|
* empty string for GNU, complicated
|
|
* - seems to be a single value (if any)
|
|
* - target_endian: single value; "little" or "big"
|
|
* - target_pointer_width: single value, "32" for 32-bit pointers, etc.
|
|
* - target_vendor, single value
|
|
* - test: set when testing is being done
|
|
* - again, seems similar to a "is defined" rather than "is equal to" like
|
|
* unix
|
|
* - debug_assertions: seems to "is defined"
|
|
* - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is
|
|
* defined"
|
|
*/
|
|
};
|
|
|
|
// Defines compiler options (e.g. dump, etc.).
|
|
struct CompileOptions
|
|
{
|
|
enum DumpOption
|
|
{
|
|
LEXER_DUMP,
|
|
AST_DUMP_PRETTY,
|
|
REGISTER_PLUGINS_DUMP,
|
|
INJECTION_DUMP,
|
|
EXPANSION_DUMP,
|
|
RESOLUTION_DUMP,
|
|
TARGET_OPTION_DUMP,
|
|
HIR_DUMP,
|
|
HIR_DUMP_PRETTY,
|
|
BIR_DUMP,
|
|
INTERNAL_DUMP,
|
|
};
|
|
|
|
std::set<DumpOption> dump_options;
|
|
|
|
/* List of node that is not print during the dump of the ast with internal
|
|
* comment */
|
|
std::set<std::string> excluded_node;
|
|
|
|
/* configuration options - actually useful for conditional compilation and
|
|
* whatever data related to target arch, features, os, family, env, endian,
|
|
* pointer width, vendor */
|
|
TargetOptions target_data;
|
|
std::string crate_name;
|
|
bool crate_name_set_manually = false;
|
|
bool enable_test = false;
|
|
bool debug_assertions = false;
|
|
std::string metadata_output_path;
|
|
|
|
enum class Edition
|
|
{
|
|
E2015 = 0,
|
|
E2018,
|
|
E2021,
|
|
} edition
|
|
= Edition::E2015;
|
|
|
|
enum class CompileStep
|
|
{
|
|
Ast,
|
|
AttributeCheck,
|
|
Expansion,
|
|
ASTValidation,
|
|
FeatureGating,
|
|
NameResolution,
|
|
Lowering,
|
|
TypeCheck,
|
|
Privacy,
|
|
Unsafety,
|
|
Const,
|
|
BorrowCheck,
|
|
Compilation,
|
|
End,
|
|
} compile_until
|
|
= CompileStep::End;
|
|
|
|
enum class PanicStrategy
|
|
{
|
|
Unwind,
|
|
Abort,
|
|
} panic_strategy
|
|
= PanicStrategy::Unwind;
|
|
|
|
bool dump_option_enabled (DumpOption option) const
|
|
{
|
|
return dump_options.find (option) != dump_options.end ();
|
|
}
|
|
|
|
void enable_dump_option (DumpOption option) { dump_options.insert (option); }
|
|
|
|
void enable_all_dump_options ()
|
|
{
|
|
enable_dump_option (DumpOption::LEXER_DUMP);
|
|
enable_dump_option (DumpOption::AST_DUMP_PRETTY);
|
|
enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP);
|
|
enable_dump_option (DumpOption::INJECTION_DUMP);
|
|
enable_dump_option (DumpOption::EXPANSION_DUMP);
|
|
enable_dump_option (DumpOption::RESOLUTION_DUMP);
|
|
enable_dump_option (DumpOption::TARGET_OPTION_DUMP);
|
|
enable_dump_option (DumpOption::HIR_DUMP);
|
|
enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
|
|
enable_dump_option (DumpOption::BIR_DUMP);
|
|
enable_dump_option (DumpOption::INTERNAL_DUMP);
|
|
}
|
|
|
|
void add_excluded (std::string node)
|
|
{
|
|
rust_assert (!node.empty ());
|
|
excluded_node.insert (node);
|
|
}
|
|
|
|
const std::set<std::string> get_excluded () const { return excluded_node; }
|
|
|
|
void set_crate_name (std::string name)
|
|
{
|
|
rust_assert (!name.empty ());
|
|
|
|
crate_name = std::move (name);
|
|
}
|
|
|
|
const std::string &get_crate_name () const
|
|
{
|
|
rust_assert (!crate_name.empty ());
|
|
return crate_name;
|
|
}
|
|
|
|
void set_edition (int raw_edition)
|
|
{
|
|
edition = static_cast<Edition> (raw_edition);
|
|
}
|
|
|
|
const Edition &get_edition () const { return edition; }
|
|
|
|
void set_crate_type (int raw_type) { target_data.set_crate_type (raw_type); }
|
|
|
|
bool is_proc_macro () const
|
|
{
|
|
return target_data.get_crate_type ()
|
|
== TargetOptions::CrateType::PROC_MACRO;
|
|
}
|
|
|
|
void set_compile_step (int raw_step)
|
|
{
|
|
compile_until = static_cast<CompileStep> (raw_step);
|
|
}
|
|
|
|
const CompileStep &get_compile_until () const { return compile_until; }
|
|
|
|
void set_panic_strategy (int strategy)
|
|
{
|
|
panic_strategy = static_cast<PanicStrategy> (strategy);
|
|
}
|
|
|
|
const PanicStrategy &get_panic_strategy () const { return panic_strategy; }
|
|
|
|
void set_metadata_output (const std::string &path)
|
|
{
|
|
metadata_output_path = path;
|
|
}
|
|
|
|
const std::string &get_metadata_output () const
|
|
{
|
|
return metadata_output_path;
|
|
}
|
|
|
|
bool metadata_output_path_set () const
|
|
{
|
|
return !metadata_output_path.empty ();
|
|
}
|
|
};
|
|
|
|
/* Defines a compiler session. This is for a single compiler invocation, so
|
|
* potentially includes parsing multiple crates. */
|
|
struct Session
|
|
{
|
|
CompileOptions options;
|
|
/* This should really be in a per-crate storage area but it is wiped with
|
|
* every file so eh. */
|
|
std::string injected_crate_name;
|
|
std::map<std::string, std::string> extern_crates;
|
|
|
|
/* extra files get included during late stages of compilation (e.g. macro
|
|
* expansion) */
|
|
std::vector<std::string> extra_files;
|
|
|
|
// backend linemap
|
|
Linemap *linemap;
|
|
|
|
// mappings
|
|
Analysis::Mappings &mappings;
|
|
|
|
public:
|
|
/* Get a reference to the static session instance */
|
|
static Session &get_instance ();
|
|
|
|
~Session () = default;
|
|
|
|
/* This initializes the compiler session. Corresponds to langhook
|
|
* grs_langhook_init(). Note that this is called after option handling. */
|
|
void init ();
|
|
|
|
// delete those constructors so we don't access the singleton in any
|
|
// other way than via `get_instance()`
|
|
Session (Session const &) = delete;
|
|
void operator= (Session const &) = delete;
|
|
|
|
bool handle_option (enum opt_code code, const char *arg, HOST_WIDE_INT value,
|
|
int kind, location_t loc,
|
|
const struct cl_option_handlers *handlers);
|
|
void handle_input_files (int num_files, const char **files);
|
|
void init_options ();
|
|
void handle_crate_name (const char *filename, const AST::Crate &parsed_crate);
|
|
|
|
/* This function saves the filename data into the session manager using the
|
|
* `move` semantics, and returns a C-style string referencing the input
|
|
* std::string */
|
|
inline const char *include_extra_file (std::string filename)
|
|
{
|
|
extra_files.push_back (std::move (filename));
|
|
return extra_files.back ().c_str ();
|
|
}
|
|
|
|
NodeId load_extern_crate (const std::string &crate_name, location_t locus);
|
|
|
|
private:
|
|
Session () : mappings (Analysis::Mappings::get ()) {}
|
|
void compile_crate (const char *filename);
|
|
bool enable_dump (std::string arg);
|
|
|
|
void dump_lex (Parser<Lexer> &parser) const;
|
|
void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const;
|
|
void dump_ast_pretty_internal (AST::Crate &crate) const;
|
|
void dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const;
|
|
void dump_hir (HIR::Crate &crate) const;
|
|
void dump_hir_pretty (HIR::Crate &crate) const;
|
|
|
|
void handle_excluded_node (std::string arg);
|
|
|
|
// pipeline stages - TODO maybe move?
|
|
/* Register plugins pipeline stage. TODO maybe move to another object?
|
|
* Currently dummy stage. In future will handle attribute injection
|
|
* (top-level inner attribute creation from command line arguments), setting
|
|
* options maybe, registering lints maybe, loading plugins maybe. */
|
|
void register_plugins (AST::Crate &crate);
|
|
|
|
/* Injection pipeline stage. TODO maybe move to another object? Maybe have
|
|
* some lint checks (in future, obviously), register builtin macros, crate
|
|
* injection. */
|
|
void injection (AST::Crate &crate);
|
|
|
|
/* Expansion pipeline stage. TODO maybe move to another object? Expands all
|
|
* macros, maybe build test harness in future, AST validation, maybe create
|
|
* macro crate (if not rustdoc).*/
|
|
void expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx);
|
|
|
|
// handle cfg_option
|
|
bool handle_cfg_option (std::string &data);
|
|
|
|
bool handle_extern_option (std::string &data);
|
|
};
|
|
|
|
} // namespace Rust
|
|
|
|
#if CHECKING_P
|
|
namespace selftest {
|
|
extern void rust_crate_name_validation_test (void);
|
|
}
|
|
#endif // CHECKING_P
|
|
|
|
#endif
|