1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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"
20 #ifndef RUST_SESSION_MANAGER_H
21 #define RUST_SESSION_MANAGER_H
23 #include "rust-linemap.h"
24 #include "rust-backend.h"
25 #include "rust-hir-map.h"
26 #include "safe-ctype.h"
29 #include "rust-system.h"
30 #include "coretypes.h"
36 // parser forward decl
37 template <typename ManagedTokenSource
> class Parser
;
48 /* Data related to target, most useful for conditional compilation and
52 /* TODO: maybe make private and access through helpers to allow changes to
54 std::unordered_map
<std::string
, std::unordered_set
<tl::optional
<std::string
>>>
70 void set_crate_type (int raw_type
)
72 crate_type
= static_cast<CrateType
> (raw_type
);
75 const CrateType
&get_crate_type () const { return crate_type
; }
77 // Returns whether a key is defined in the feature set.
78 bool has_key (std::string key
) const
80 auto it
= features
.find (key
);
81 return it
!= features
.end ()
82 && it
->second
.find (tl::nullopt
) != it
->second
.end ();
85 // Returns whether a key exists with the given value in the feature set.
86 bool has_key_value_pair (std::string key
, std::string value
) const
88 auto it
= features
.find (key
);
89 if (it
!= features
.end ())
91 auto set
= it
->second
;
92 auto it2
= set
.find (value
);
93 if (it2
!= set
.end ())
99 /* Returns the singular value from the key, or if the key has multiple, an
101 std::string
get_singular_value (std::string key
) const
103 auto it
= features
.find (key
);
104 if (it
!= features
.end ())
106 auto set
= it
->second
;
107 if (set
.size () == 1 && set
.begin ()->has_value ())
108 return set
.begin ()->value ();
113 /* Returns all values associated with a key (including none), or an empty
114 * set if no key is found. */
115 std::unordered_set
<std::string
> get_values_for_key (std::string key
) const
117 std::unordered_set
<std::string
> ret
;
119 auto it
= features
.find (key
);
120 if (it
== features
.end ())
123 for (auto &val
: it
->second
)
124 if (val
.has_value ())
125 ret
.insert (val
.value ());
130 /* Inserts a key (no value) into the feature set. This will do nothing if
131 * the key already exists. This returns whether the insertion was successful
132 * (i.e. whether key already existed). */
133 bool insert_key (std::string key
)
135 auto it
= features
.find (key
);
137 if (it
== features
.end ())
141 std::make_pair (std::move (key
),
142 std::unordered_set
<tl::optional
<std::string
>> ()))
145 return it
->second
.insert (tl::nullopt
).second
;
148 // Inserts a key-value pair into the feature set.
149 void insert_key_value_pair (std::string key
, std::string value
)
151 auto it
= features
.find (key
);
153 if (it
== features
.end ())
157 std::make_pair (std::move (key
),
158 std::unordered_set
<tl::optional
<std::string
>> ()))
161 it
->second
.insert (std::move (value
));
164 // Dump all target options to stderr.
165 void dump_target_options () const;
167 /* Creates derived values and implicit enables after all target info is
168 * added (e.g. "unix"). */
169 void init_derived_values ();
171 /* Enables all requirements for the feature given, and will enable feature
172 * itself if not enabled. */
173 void enable_implicit_feature_reqs (std::string feature
);
175 /* According to reference, Rust uses either multi-map key-values or just
176 * values (although values may be aliases for a key-value value). This seems
177 * like overkill. Thus, depending on whether the attributes used in cfg are
178 * fixed or not, I think I'll either put each non-multimap "key-value" as a
179 * separate field and have the multimap "key-values" in a regular map for
180 * that one key, or actually use a multimap.
182 * rustc itself uses a set of key-value tuples where the second tuple
183 * element is optional. This gets rid of the requirement to make a
184 * multi-map, I guess, but seems like it might make search slow (unless all
185 * "is defined"-only ones have empty string as second element). */
187 * - target_arch: single value
188 * - target_feature: multiple values possible
189 * - target_os: single value
190 * - target_family: single value (or no value?)
191 * - unix: set when target_family = "unix"
192 * - windows: set when target_family = "windows"
193 * - if these are just syntactic sugar, then maybe have a separate set or
194 * map for this kind of stuff
195 * - target_env: set when needed for disambiguation about ABI - usually
196 * empty string for GNU, complicated
197 * - seems to be a single value (if any)
198 * - target_endian: single value; "little" or "big"
199 * - target_pointer_width: single value, "32" for 32-bit pointers, etc.
200 * - target_vendor, single value
201 * - test: set when testing is being done
202 * - again, seems similar to a "is defined" rather than "is equal to" like
204 * - debug_assertions: seems to "is defined"
205 * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is
210 // Defines compiler options (e.g. dump, etc.).
211 struct CompileOptions
217 REGISTER_PLUGINS_DUMP
,
227 std::set
<DumpOption
> dump_options
;
229 /* configuration options - actually useful for conditional compilation and
230 * whatever data related to target arch, features, os, family, env, endian,
231 * pointer width, vendor */
232 TargetOptions target_data
;
233 std::string crate_name
;
234 bool crate_name_set_manually
= false;
235 bool enable_test
= false;
236 bool debug_assertions
= false;
237 std::string metadata_output_path
;
247 enum class CompileStep
266 bool dump_option_enabled (DumpOption option
) const
268 return dump_options
.find (option
) != dump_options
.end ();
271 void enable_dump_option (DumpOption option
) { dump_options
.insert (option
); }
273 void enable_all_dump_options ()
275 enable_dump_option (DumpOption::LEXER_DUMP
);
276 enable_dump_option (DumpOption::AST_DUMP_PRETTY
);
277 enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP
);
278 enable_dump_option (DumpOption::INJECTION_DUMP
);
279 enable_dump_option (DumpOption::EXPANSION_DUMP
);
280 enable_dump_option (DumpOption::RESOLUTION_DUMP
);
281 enable_dump_option (DumpOption::TARGET_OPTION_DUMP
);
282 enable_dump_option (DumpOption::HIR_DUMP
);
283 enable_dump_option (DumpOption::HIR_DUMP_PRETTY
);
284 enable_dump_option (DumpOption::BIR_DUMP
);
287 void set_crate_name (std::string name
)
289 rust_assert (!name
.empty ());
291 crate_name
= std::move (name
);
294 const std::string
&get_crate_name () const
296 rust_assert (!crate_name
.empty ());
300 void set_edition (int raw_edition
)
302 edition
= static_cast<Edition
> (raw_edition
);
305 const Edition
&get_edition () const { return edition
; }
307 void set_crate_type (int raw_type
) { target_data
.set_crate_type (raw_type
); }
309 bool is_proc_macro () const
311 return target_data
.get_crate_type ()
312 == TargetOptions::CrateType::PROC_MACRO
;
315 void set_compile_step (int raw_step
)
317 compile_until
= static_cast<CompileStep
> (raw_step
);
320 const CompileStep
&get_compile_until () const { return compile_until
; }
322 void set_metadata_output (const std::string
&path
)
324 metadata_output_path
= path
;
327 const std::string
&get_metadata_output () const
329 return metadata_output_path
;
332 bool metadata_output_path_set () const
334 return !metadata_output_path
.empty ();
338 /* Defines a compiler session. This is for a single compiler invocation, so
339 * potentially includes parsing multiple crates. */
342 CompileOptions options
;
343 /* This should really be in a per-crate storage area but it is wiped with
344 * every file so eh. */
345 std::string injected_crate_name
;
346 std::map
<std::string
, std::string
> extern_crates
;
348 /* extra files get included during late stages of compilation (e.g. macro
350 std::vector
<std::string
> extra_files
;
356 Analysis::Mappings
*mappings
;
359 /* Get a reference to the static session instance */
360 static Session
&get_instance ();
362 Session () = default;
363 ~Session () = default;
365 /* This initializes the compiler session. Corresponds to langhook
366 * grs_langhook_init(). Note that this is called after option handling. */
369 // delete those constructors so we don't access the singleton in any
370 // other way than via `get_instance()`
371 Session (Session
const &) = delete;
372 void operator= (Session
const &) = delete;
374 bool handle_option (enum opt_code code
, const char *arg
, HOST_WIDE_INT value
,
375 int kind
, location_t loc
,
376 const struct cl_option_handlers
*handlers
);
377 void handle_input_files (int num_files
, const char **files
);
378 void init_options ();
379 void handle_crate_name (const AST::Crate
&parsed_crate
);
381 /* This function saves the filename data into the session manager using the
382 * `move` semantics, and returns a C-style string referencing the input
384 inline const char *include_extra_file (std::string filename
)
386 extra_files
.push_back (std::move (filename
));
387 return extra_files
.back ().c_str ();
390 NodeId
load_extern_crate (const std::string
&crate_name
, location_t locus
);
393 void compile_crate (const char *filename
);
394 bool enable_dump (std::string arg
);
396 void dump_lex (Parser
<Lexer
> &parser
) const;
397 void dump_ast_pretty (AST::Crate
&crate
, bool expanded
= false) const;
398 void dump_hir (HIR::Crate
&crate
) const;
399 void dump_hir_pretty (HIR::Crate
&crate
) const;
401 // pipeline stages - TODO maybe move?
402 /* Register plugins pipeline stage. TODO maybe move to another object?
403 * Currently dummy stage. In future will handle attribute injection
404 * (top-level inner attribute creation from command line arguments), setting
405 * options maybe, registering lints maybe, loading plugins maybe. */
406 void register_plugins (AST::Crate
&crate
);
408 /* Injection pipeline stage. TODO maybe move to another object? Maybe have
409 * some lint checks (in future, obviously), register builtin macros, crate
411 void injection (AST::Crate
&crate
);
413 /* Expansion pipeline stage. TODO maybe move to another object? Expands all
414 * macros, maybe build test harness in future, AST validation, maybe create
415 * macro crate (if not rustdoc).*/
416 void expansion (AST::Crate
&crate
);
419 bool handle_cfg_option (std::string
&data
);
421 bool handle_extern_option (std::string
&data
);
429 rust_crate_name_validation_test (void);