Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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 : : #include "optional.h"
34 : :
35 : : namespace Rust {
36 : : // parser forward decl
37 : : template <typename ManagedTokenSource> class Parser;
38 : : class Lexer;
39 : : // crate forward decl
40 : : namespace AST {
41 : : struct Crate;
42 : : }
43 : : // crate forward decl
44 : : namespace HIR {
45 : : class Crate;
46 : : }
47 : :
48 : : /* Data related to target, most useful for conditional compilation and
49 : : * whatever. */
50 : : struct TargetOptions
51 : : {
52 : : /* TODO: maybe make private and access through helpers to allow changes to
53 : : * impl */
54 : : std::unordered_map<std::string, std::unordered_set<tl::optional<std::string>>>
55 : : features;
56 : :
57 : : enum class CrateType
58 : : {
59 : : BIN = 0,
60 : : LIB,
61 : : RLIB,
62 : : DYLIB,
63 : : CDYLIB,
64 : : STATICLIB,
65 : : PROC_MACRO
66 : : } crate_type
67 : : = CrateType::BIN;
68 : :
69 : : public:
70 : 21 : void set_crate_type (int raw_type)
71 : : {
72 : 21 : crate_type = static_cast<CrateType> (raw_type);
73 : : }
74 : :
75 : : const CrateType &get_crate_type () const { return crate_type; }
76 : :
77 : : // Returns whether a key is defined in the feature set.
78 : 214 : bool has_key (std::string key) const
79 : : {
80 : 214 : auto it = features.find (key);
81 : 214 : return it != features.end ()
82 : 337 : && it->second.find (tl::nullopt) != it->second.end ();
83 : : }
84 : :
85 : : // Returns whether a key exists with the given value in the feature set.
86 : 828 : bool has_key_value_pair (std::string key, std::string value) const
87 : : {
88 : 828 : auto it = features.find (key);
89 : 828 : if (it != features.end ())
90 : : {
91 : 814 : auto set = it->second;
92 : 814 : auto it2 = set.find (value);
93 : 814 : if (it2 != set.end ())
94 : 814 : return true;
95 : 814 : }
96 : : return false;
97 : : }
98 : :
99 : : /* Returns the singular value from the key, or if the key has multiple, an
100 : : * empty string. */
101 : : std::string get_singular_value (std::string key) const
102 : : {
103 : : auto it = features.find (key);
104 : : if (it != features.end ())
105 : : {
106 : : auto set = it->second;
107 : : if (set.size () == 1 && set.begin ()->has_value ())
108 : : return set.begin ()->value ();
109 : : }
110 : : return "";
111 : : }
112 : :
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
116 : : {
117 : : std::unordered_set<std::string> ret;
118 : :
119 : : auto it = features.find (key);
120 : : if (it == features.end ())
121 : : return {};
122 : :
123 : : for (auto &val : it->second)
124 : : if (val.has_value ())
125 : : ret.insert (val.value ());
126 : :
127 : : return ret;
128 : : }
129 : :
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 : 63 : bool insert_key (std::string key)
134 : : {
135 : 63 : auto it = features.find (key);
136 : :
137 : 63 : if (it == features.end ())
138 : 63 : it
139 : 63 : = features
140 : 63 : .insert (
141 : 126 : std::make_pair (std::move (key),
142 : 189 : std::unordered_set<tl::optional<std::string>> ()))
143 : : .first;
144 : :
145 : 63 : return it->second.insert (tl::nullopt).second;
146 : : }
147 : :
148 : : // Inserts a key-value pair into the feature set.
149 : 40658 : void insert_key_value_pair (std::string key, std::string value)
150 : : {
151 : 40658 : auto it = features.find (key);
152 : :
153 : 40658 : if (it == features.end ())
154 : 29570 : it
155 : 29570 : = features
156 : 29570 : .insert (
157 : 59140 : std::make_pair (std::move (key),
158 : 59140 : std::unordered_set<tl::optional<std::string>> ()))
159 : : .first;
160 : :
161 : 40658 : it->second.insert (std::move (value));
162 : 40658 : }
163 : :
164 : : // Dump all target options to stderr.
165 : : void dump_target_options () const;
166 : :
167 : : /* Creates derived values and implicit enables after all target info is
168 : : * added (e.g. "unix"). */
169 : : void init_derived_values ();
170 : :
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);
174 : :
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.
181 : : *
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). */
186 : : /* cfg attributes:
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
203 : : * unix
204 : : * - debug_assertions: seems to "is defined"
205 : : * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is
206 : : * defined"
207 : : */
208 : : };
209 : :
210 : : // Defines compiler options (e.g. dump, etc.).
211 : : struct CompileOptions
212 : : {
213 : : enum DumpOption
214 : : {
215 : : LEXER_DUMP,
216 : : AST_DUMP_PRETTY,
217 : : REGISTER_PLUGINS_DUMP,
218 : : INJECTION_DUMP,
219 : : EXPANSION_DUMP,
220 : : RESOLUTION_DUMP,
221 : : TARGET_OPTION_DUMP,
222 : : HIR_DUMP,
223 : : HIR_DUMP_PRETTY,
224 : : BIR_DUMP,
225 : : };
226 : :
227 : : std::set<DumpOption> dump_options;
228 : :
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;
238 : :
239 : : enum class Edition
240 : : {
241 : : E2015 = 0,
242 : : E2018,
243 : : E2021,
244 : : } edition
245 : : = Edition::E2015;
246 : :
247 : : enum class CompileStep
248 : : {
249 : : Ast,
250 : : AttributeCheck,
251 : : Expansion,
252 : : ASTValidation,
253 : : FeatureGating,
254 : : NameResolution,
255 : : Lowering,
256 : : TypeCheck,
257 : : Privacy,
258 : : Unsafety,
259 : : Const,
260 : : BorrowCheck,
261 : : Compilation,
262 : : End,
263 : : } compile_until
264 : : = CompileStep::End;
265 : :
266 : 32388 : bool dump_option_enabled (DumpOption option) const
267 : : {
268 : 25240 : return dump_options.find (option) != dump_options.end ();
269 : : }
270 : :
271 : 0 : void enable_dump_option (DumpOption option) { dump_options.insert (option); }
272 : :
273 : 0 : void enable_all_dump_options ()
274 : : {
275 : 0 : enable_dump_option (DumpOption::LEXER_DUMP);
276 : 0 : enable_dump_option (DumpOption::AST_DUMP_PRETTY);
277 : 0 : enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP);
278 : 0 : enable_dump_option (DumpOption::INJECTION_DUMP);
279 : 0 : enable_dump_option (DumpOption::EXPANSION_DUMP);
280 : 0 : enable_dump_option (DumpOption::RESOLUTION_DUMP);
281 : 0 : enable_dump_option (DumpOption::TARGET_OPTION_DUMP);
282 : 0 : enable_dump_option (DumpOption::HIR_DUMP);
283 : 0 : enable_dump_option (DumpOption::HIR_DUMP_PRETTY);
284 : 0 : enable_dump_option (DumpOption::BIR_DUMP);
285 : 0 : }
286 : :
287 : 3705 : void set_crate_name (std::string name)
288 : : {
289 : 3705 : rust_assert (!name.empty ());
290 : :
291 : 3705 : crate_name = std::move (name);
292 : 3705 : }
293 : :
294 : 3696 : const std::string &get_crate_name () const
295 : : {
296 : 3696 : rust_assert (!crate_name.empty ());
297 : 3696 : return crate_name;
298 : : }
299 : :
300 : 6 : void set_edition (int raw_edition)
301 : : {
302 : 6 : edition = static_cast<Edition> (raw_edition);
303 : 6 : }
304 : :
305 : : const Edition &get_edition () const { return edition; }
306 : :
307 : 21 : void set_crate_type (int raw_type) { target_data.set_crate_type (raw_type); }
308 : :
309 : 12870 : bool is_proc_macro () const
310 : : {
311 : 12870 : return target_data.get_crate_type ()
312 : : == TargetOptions::CrateType::PROC_MACRO;
313 : : }
314 : :
315 : 19 : void set_compile_step (int raw_step)
316 : : {
317 : 19 : compile_until = static_cast<CompileStep> (raw_step);
318 : 19 : }
319 : :
320 : : const CompileStep &get_compile_until () const { return compile_until; }
321 : :
322 : 0 : void set_metadata_output (const std::string &path)
323 : : {
324 : 0 : metadata_output_path = path;
325 : : }
326 : :
327 : 0 : const std::string &get_metadata_output () const
328 : : {
329 : 0 : return metadata_output_path;
330 : : }
331 : :
332 : 3279 : bool metadata_output_path_set () const
333 : : {
334 : 3279 : return !metadata_output_path.empty ();
335 : : }
336 : : };
337 : :
338 : : /* Defines a compiler session. This is for a single compiler invocation, so
339 : : * potentially includes parsing multiple crates. */
340 : : struct Session
341 : : {
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;
347 : :
348 : : /* extra files get included during late stages of compilation (e.g. macro
349 : : * expansion) */
350 : : std::vector<std::string> extra_files;
351 : :
352 : : // backend linemap
353 : : Linemap *linemap;
354 : :
355 : : // mappings
356 : : Analysis::Mappings *mappings;
357 : :
358 : : public:
359 : : /* Get a reference to the static session instance */
360 : : static Session &get_instance ();
361 : :
362 : 3697 : Session () = default;
363 : 3697 : ~Session () = default;
364 : :
365 : : /* This initializes the compiler session. Corresponds to langhook
366 : : * grs_langhook_init(). Note that this is called after option handling. */
367 : : void init ();
368 : :
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;
373 : :
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);
380 : :
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
383 : : * std::string */
384 : 1 : inline const char *include_extra_file (std::string filename)
385 : : {
386 : 1 : extra_files.push_back (std::move (filename));
387 : 1 : return extra_files.back ().c_str ();
388 : : }
389 : :
390 : : NodeId load_extern_crate (const std::string &crate_name, location_t locus);
391 : :
392 : : private:
393 : : void compile_crate (const char *filename);
394 : : bool enable_dump (std::string arg);
395 : :
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;
400 : :
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);
407 : :
408 : : /* Injection pipeline stage. TODO maybe move to another object? Maybe have
409 : : * some lint checks (in future, obviously), register builtin macros, crate
410 : : * injection. */
411 : : void injection (AST::Crate &crate);
412 : :
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);
417 : :
418 : : // handle cfg_option
419 : : bool handle_cfg_option (std::string &data);
420 : :
421 : : bool handle_extern_option (std::string &data);
422 : : };
423 : :
424 : : } // namespace Rust
425 : :
426 : : #if CHECKING_P
427 : : namespace selftest {
428 : : extern void
429 : : rust_crate_name_validation_test (void);
430 : : }
431 : : #endif // CHECKING_P
432 : :
433 : : #endif
|