Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 42 : void set_crate_type (int raw_type)
72 : : {
73 : 42 : 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 : 290 : bool has_key (std::string key) const
80 : : {
81 : 290 : auto it = features.find (key);
82 : 290 : return it != features.end ()
83 : 457 : && 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 : 2440 : bool has_key_value_pair (std::string key, std::string value) const
88 : : {
89 : 2440 : auto it = features.find (key);
90 : 2440 : if (it != features.end ())
91 : : {
92 : 2422 : auto set = it->second;
93 : 2422 : auto it2 = set.find (value);
94 : 2422 : if (it2 != set.end ())
95 : 2370 : return true;
96 : 2422 : }
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 : 76 : bool insert_key (std::string key)
135 : : {
136 : 76 : auto it = features.find (key);
137 : :
138 : 76 : if (it == features.end ())
139 : 76 : it
140 : 76 : = features
141 : 76 : .insert (
142 : 76 : std::make_pair (std::move (key),
143 : 152 : std::unordered_set<tl::optional<std::string>> ()))
144 : : .first;
145 : :
146 : 76 : return it->second.insert (tl::nullopt).second;
147 : : }
148 : :
149 : : // Inserts a key-value pair into the feature set.
150 : 57710 : void insert_key_value_pair (std::string key, std::string value)
151 : : {
152 : 57710 : auto it = features.find (key);
153 : :
154 : 57710 : if (it == features.end ())
155 : 41972 : it
156 : 41972 : = features
157 : 41972 : .insert (
158 : 41972 : std::make_pair (std::move (key),
159 : 83944 : std::unordered_set<tl::optional<std::string>> ()))
160 : : .first;
161 : :
162 : 57710 : it->second.insert (std::move (value));
163 : 57710 : }
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 : : };
227 : :
228 : : std::set<DumpOption> dump_options;
229 : :
230 : : /* configuration options - actually useful for conditional compilation and
231 : : * whatever data related to target arch, features, os, family, env, endian,
232 : : * pointer width, vendor */
233 : : TargetOptions target_data;
234 : : std::string crate_name;
235 : : bool crate_name_set_manually = false;
236 : : bool enable_test = false;
237 : : bool debug_assertions = false;
238 : : std::string metadata_output_path;
239 : :
240 : : enum class Edition
241 : : {
242 : : E2015 = 0,
243 : : E2018,
244 : : E2021,
245 : : } edition
246 : : = Edition::E2015;
247 : :
248 : : enum class CompileStep
249 : : {
250 : : Ast,
251 : : AttributeCheck,
252 : : Expansion,
253 : : ASTValidation,
254 : : FeatureGating,
255 : : NameResolution,
256 : : Lowering,
257 : : TypeCheck,
258 : : Privacy,
259 : : Unsafety,
260 : : Const,
261 : : BorrowCheck,
262 : : Compilation,
263 : : End,
264 : : } compile_until
265 : : = CompileStep::End;
266 : :
267 : : enum class PanicStrategy
268 : : {
269 : : Unwind,
270 : : Abort,
271 : : } panic_strategy
272 : : = PanicStrategy::Unwind;
273 : :
274 : 45553 : bool dump_option_enabled (DumpOption option) const
275 : : {
276 : 35529 : return dump_options.find (option) != dump_options.end ();
277 : : }
278 : :
279 : 0 : void enable_dump_option (DumpOption option) { dump_options.insert (option); }
280 : :
281 : 0 : void enable_all_dump_options ()
282 : : {
283 : 0 : enable_dump_option (DumpOption::LEXER_DUMP);
284 : 0 : enable_dump_option (DumpOption::AST_DUMP_PRETTY);
285 : 0 : enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP);
286 : 0 : enable_dump_option (DumpOption::INJECTION_DUMP);
287 : 0 : enable_dump_option (DumpOption::EXPANSION_DUMP);
288 : 0 : enable_dump_option (DumpOption::RESOLUTION_DUMP);
289 : 0 : enable_dump_option (DumpOption::TARGET_OPTION_DUMP);
290 : 0 : enable_dump_option (DumpOption::HIR_DUMP);
291 : 0 : enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
292 : 0 : enable_dump_option (DumpOption::BIR_DUMP);
293 : 0 : }
294 : :
295 : 5246 : void set_crate_name (std::string name)
296 : : {
297 : 5246 : rust_assert (!name.empty ());
298 : :
299 : 5246 : crate_name = std::move (name);
300 : 5246 : }
301 : :
302 : 10330 : const std::string &get_crate_name () const
303 : : {
304 : 10330 : rust_assert (!crate_name.empty ());
305 : 10330 : return crate_name;
306 : : }
307 : :
308 : 11 : void set_edition (int raw_edition)
309 : : {
310 : 11 : edition = static_cast<Edition> (raw_edition);
311 : 11 : }
312 : :
313 : : const Edition &get_edition () const { return edition; }
314 : :
315 : 42 : void set_crate_type (int raw_type) { target_data.set_crate_type (raw_type); }
316 : :
317 : 17042 : bool is_proc_macro () const
318 : : {
319 : 17042 : return target_data.get_crate_type ()
320 : : == TargetOptions::CrateType::PROC_MACRO;
321 : : }
322 : :
323 : 63 : void set_compile_step (int raw_step)
324 : : {
325 : 63 : compile_until = static_cast<CompileStep> (raw_step);
326 : 63 : }
327 : :
328 : : const CompileStep &get_compile_until () const { return compile_until; }
329 : :
330 : 0 : void set_panic_strategy (int strategy)
331 : : {
332 : 0 : panic_strategy = static_cast<PanicStrategy> (strategy);
333 : 0 : }
334 : :
335 : : const PanicStrategy &get_panic_strategy () const { return panic_strategy; }
336 : :
337 : 0 : void set_metadata_output (const std::string &path)
338 : : {
339 : 0 : metadata_output_path = path;
340 : : }
341 : :
342 : 0 : const std::string &get_metadata_output () const
343 : : {
344 : 0 : return metadata_output_path;
345 : : }
346 : :
347 : 4363 : bool metadata_output_path_set () const
348 : : {
349 : 4363 : return !metadata_output_path.empty ();
350 : : }
351 : : };
352 : :
353 : : /* Defines a compiler session. This is for a single compiler invocation, so
354 : : * potentially includes parsing multiple crates. */
355 : : struct Session
356 : : {
357 : : CompileOptions options;
358 : : /* This should really be in a per-crate storage area but it is wiped with
359 : : * every file so eh. */
360 : : std::string injected_crate_name;
361 : : std::map<std::string, std::string> extern_crates;
362 : :
363 : : /* extra files get included during late stages of compilation (e.g. macro
364 : : * expansion) */
365 : : std::vector<std::string> extra_files;
366 : :
367 : : // backend linemap
368 : : Linemap *linemap;
369 : :
370 : : // mappings
371 : : Analysis::Mappings &mappings;
372 : :
373 : : public:
374 : : /* Get a reference to the static session instance */
375 : : static Session &get_instance ();
376 : :
377 : 5248 : ~Session () = default;
378 : :
379 : : /* This initializes the compiler session. Corresponds to langhook
380 : : * grs_langhook_init(). Note that this is called after option handling. */
381 : : void init ();
382 : :
383 : : // delete those constructors so we don't access the singleton in any
384 : : // other way than via `get_instance()`
385 : : Session (Session const &) = delete;
386 : : void operator= (Session const &) = delete;
387 : :
388 : : bool handle_option (enum opt_code code, const char *arg, HOST_WIDE_INT value,
389 : : int kind, location_t loc,
390 : : const struct cl_option_handlers *handlers);
391 : : void handle_input_files (int num_files, const char **files);
392 : : void init_options ();
393 : : void handle_crate_name (const char *filename, const AST::Crate &parsed_crate);
394 : :
395 : : /* This function saves the filename data into the session manager using the
396 : : * `move` semantics, and returns a C-style string referencing the input
397 : : * std::string */
398 : 10 : inline const char *include_extra_file (std::string filename)
399 : : {
400 : 10 : extra_files.push_back (std::move (filename));
401 : 10 : return extra_files.back ().c_str ();
402 : : }
403 : :
404 : : NodeId load_extern_crate (const std::string &crate_name, location_t locus);
405 : :
406 : : private:
407 : 5248 : Session () : mappings (Analysis::Mappings::get ()) {}
408 : : void compile_crate (const char *filename);
409 : : bool enable_dump (std::string arg);
410 : :
411 : : void dump_lex (Parser<Lexer> &parser) const;
412 : : void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const;
413 : : void dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const;
414 : : void dump_hir (HIR::Crate &crate) const;
415 : : void dump_hir_pretty (HIR::Crate &crate) const;
416 : :
417 : : // pipeline stages - TODO maybe move?
418 : : /* Register plugins pipeline stage. TODO maybe move to another object?
419 : : * Currently dummy stage. In future will handle attribute injection
420 : : * (top-level inner attribute creation from command line arguments), setting
421 : : * options maybe, registering lints maybe, loading plugins maybe. */
422 : : void register_plugins (AST::Crate &crate);
423 : :
424 : : /* Injection pipeline stage. TODO maybe move to another object? Maybe have
425 : : * some lint checks (in future, obviously), register builtin macros, crate
426 : : * injection. */
427 : : void injection (AST::Crate &crate);
428 : :
429 : : /* Expansion pipeline stage. TODO maybe move to another object? Expands all
430 : : * macros, maybe build test harness in future, AST validation, maybe create
431 : : * macro crate (if not rustdoc).*/
432 : : void expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx);
433 : :
434 : : // handle cfg_option
435 : : bool handle_cfg_option (std::string &data);
436 : :
437 : : bool handle_extern_option (std::string &data);
438 : : };
439 : :
440 : : } // namespace Rust
441 : :
442 : : #if CHECKING_P
443 : : namespace selftest {
444 : : extern void
445 : : rust_crate_name_validation_test (void);
446 : : }
447 : : #endif // CHECKING_P
448 : :
449 : : #endif
|