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 : :
19 : : #include "rust-session-manager.h"
20 : : #include "rust-collect-lang-items.h"
21 : : #include "rust-desugar-for-loops.h"
22 : : #include "rust-desugar-question-mark.h"
23 : : #include "rust-desugar-apit.h"
24 : : #include "rust-diagnostics.h"
25 : : #include "rust-expression-yeast.h"
26 : : #include "rust-hir-pattern-analysis.h"
27 : : #include "rust-immutable-name-resolution-context.h"
28 : : #include "rust-unsafe-checker.h"
29 : : #include "rust-lex.h"
30 : : #include "rust-parse.h"
31 : : #include "rust-macro-expand.h"
32 : : #include "rust-ast-resolve.h"
33 : : #include "rust-ast-lower.h"
34 : : #include "rust-hir-type-check.h"
35 : : #include "rust-privacy-check.h"
36 : : #include "rust-const-checker.h"
37 : : #include "rust-feature-gate.h"
38 : : #include "rust-compile.h"
39 : : #include "rust-cfg-parser.h"
40 : : #include "rust-lint-scan-deadcode.h"
41 : : #include "rust-lint-unused-var.h"
42 : : #include "rust-readonly-check.h"
43 : : #include "rust-hir-dump.h"
44 : : #include "rust-ast-dump.h"
45 : : #include "rust-export-metadata.h"
46 : : #include "rust-imports.h"
47 : : #include "rust-extern-crate.h"
48 : : #include "rust-attributes.h"
49 : : #include "rust-early-name-resolver.h"
50 : : #include "rust-name-resolution-context.h"
51 : : #include "rust-early-name-resolver-2.0.h"
52 : : #include "rust-late-name-resolver-2.0.h"
53 : : #include "rust-cfg-strip.h"
54 : : #include "rust-expand-visitor.h"
55 : : #include "rust-unicode.h"
56 : : #include "rust-attribute-values.h"
57 : : #include "rust-borrow-checker.h"
58 : : #include "rust-ast-validation.h"
59 : : #include "rust-tyty-variance-analysis.h"
60 : :
61 : : #include "input.h"
62 : : #include "selftest.h"
63 : : #include "tm.h"
64 : : #include "rust-target.h"
65 : :
66 : : extern bool saw_errors (void);
67 : :
68 : : extern Linemap *rust_get_linemap ();
69 : :
70 : : namespace Rust {
71 : :
72 : : const char *kLexDumpFile = "gccrs.lex.dump";
73 : : const char *kASTDumpFile = "gccrs.ast.dump";
74 : : const char *kASTPrettyDumpFile = "gccrs.ast-pretty.dump";
75 : : const char *kASTPrettyDumpFileExpanded = "gccrs.ast-pretty-expanded.dump";
76 : : const char *kASTExpandedDumpFile = "gccrs.ast-expanded.dump";
77 : : const char *kASTmacroResolutionDumpFile = "gccrs.ast-macro-resolution.dump";
78 : : const char *kASTlabelResolutionDumpFile = "gccrs.ast-label-resolution.dump";
79 : : const char *kASTtypeResolutionDumpFile = "gccrs.ast-type-resolution.dump";
80 : : const char *kASTvalueResolutionDumpFile = "gccrs.ast-value-resolution.dump";
81 : : const char *kHIRDumpFile = "gccrs.hir.dump";
82 : : const char *kHIRPrettyDumpFile = "gccrs.hir-pretty.dump";
83 : : const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump";
84 : : const char *kTargetOptionsDumpFile = "gccrs.target-options.dump";
85 : :
86 : : const std::string kDefaultCrateName = "rust_out";
87 : : const size_t kMaxNameLength = 64;
88 : :
89 : : Session &
90 : 3701818 : Session::get_instance ()
91 : : {
92 : 3706222 : static Session instance{};
93 : 3701818 : return instance;
94 : : }
95 : :
96 : : static std::string
97 : 4388 : infer_crate_name (const std::string &filename)
98 : :
99 : : {
100 : 4388 : if (filename == "-")
101 : 0 : return kDefaultCrateName;
102 : :
103 : 4388 : std::string crate = std::string (filename);
104 : 4388 : size_t path_sep = crate.find_last_of (file_separator);
105 : :
106 : : // find the base filename
107 : 4388 : if (path_sep != std::string::npos)
108 : 4384 : crate.erase (0, path_sep + 1);
109 : :
110 : : // find the file stem name (remove file extension)
111 : 4388 : size_t ext_position = crate.find_last_of ('.');
112 : 4388 : if (ext_position != std::string::npos)
113 : 4387 : crate.erase (ext_position);
114 : :
115 : : // Replace all the '-' symbols with '_' per Rust rules
116 : 56418 : for (auto &c : crate)
117 : : {
118 : 52030 : if (c == '-')
119 : 1402 : c = '_';
120 : : }
121 : 4388 : return crate;
122 : 4388 : }
123 : :
124 : : /* Validate the crate name using the ASCII rules */
125 : :
126 : : static bool
127 : 4416 : validate_crate_name (const std::string &crate_name, Error &error)
128 : : {
129 : 4416 : tl::optional<Utf8String> utf8_name_opt
130 : 4416 : = Utf8String::make_utf8_string (crate_name);
131 : 4416 : if (!utf8_name_opt.has_value ())
132 : : {
133 : 0 : error = Error (UNDEF_LOCATION, "crate name is not a valid UTF-8 string");
134 : 0 : return false;
135 : : }
136 : :
137 : 4416 : std::vector<Codepoint> uchars = utf8_name_opt->get_chars ();
138 : 4416 : if (uchars.empty ())
139 : : {
140 : 0 : error = Error (UNDEF_LOCATION, "crate name cannot be empty");
141 : 0 : return false;
142 : : }
143 : 4416 : if (uchars.size () > kMaxNameLength)
144 : : {
145 : 0 : error = Error (UNDEF_LOCATION, "crate name cannot exceed %lu characters",
146 : 0 : (unsigned long) kMaxNameLength);
147 : 0 : return false;
148 : : }
149 : 56618 : for (Codepoint &c : uchars)
150 : : {
151 : 52210 : if (!(is_alphabetic (c.value) || is_numeric (c.value) || c.value == '_'))
152 : : {
153 : 8 : error
154 : 8 : = Error (UNDEF_LOCATION, "invalid character %qs in crate name: %qs",
155 : 8 : c.as_string ().c_str (), crate_name.c_str ());
156 : 8 : return false;
157 : : }
158 : : }
159 : : return true;
160 : 4416 : }
161 : :
162 : : void
163 : 4403 : Session::init ()
164 : : {
165 : : // initialize target hooks
166 : 4403 : targetrustm.rust_cpu_info ();
167 : 4403 : targetrustm.rust_os_info ();
168 : :
169 : : // target-independent values that should exist in all targets
170 : 4403 : options.target_data.insert_key_value_pair ("target_pointer_width",
171 : 4403 : std::to_string (POINTER_SIZE));
172 : 4403 : options.target_data.insert_key_value_pair ("target_endian", BYTES_BIG_ENDIAN
173 : 4403 : ? "big"
174 : : : "little");
175 : :
176 : : // setup singleton linemap
177 : 4403 : linemap = rust_get_linemap ();
178 : :
179 : : // setup backend to GCC GIMPLE
180 : 4403 : Backend::init ();
181 : :
182 : : // setup mappings class
183 : 4403 : mappings = Analysis::Mappings::get ();
184 : 4403 : }
185 : :
186 : : /* Initialise default options. Actually called before handle_option, unlike init
187 : : * itself. */
188 : : void
189 : 4404 : Session::init_options ()
190 : 4404 : {}
191 : :
192 : : // Handle option selection.
193 : : bool
194 : 39809 : Session::handle_option (
195 : : enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED,
196 : : int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED,
197 : : const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
198 : : {
199 : : // used to store whether results of various stuff are successful
200 : 39809 : bool ret = true;
201 : :
202 : : // Handles options as listed in lang.opt.
203 : 39809 : switch (code)
204 : : {
205 : 30826 : case OPT_I:
206 : 30826 : case OPT_L:
207 : 30826 : {
208 : : // TODO: add search path
209 : 30826 : const std::string p = std::string (arg);
210 : 30826 : add_search_path (p);
211 : 30826 : }
212 : 30826 : break;
213 : :
214 : 0 : case OPT_frust_extern_:
215 : 0 : {
216 : 0 : std::string input (arg);
217 : 0 : ret = handle_extern_option (input);
218 : 0 : }
219 : 0 : break;
220 : 12 : case OPT_frust_crate_:
221 : : // set the crate name
222 : 12 : if (arg != nullptr)
223 : : {
224 : 12 : auto error = Error (UNDEF_LOCATION, std::string ());
225 : 12 : if ((ret = validate_crate_name (arg, error)))
226 : : {
227 : 11 : options.set_crate_name (arg);
228 : 11 : options.crate_name_set_manually = true;
229 : : }
230 : : else
231 : : {
232 : 1 : rust_assert (!error.message.empty ());
233 : 1 : error.emit ();
234 : : }
235 : 12 : }
236 : : else
237 : : ret = false;
238 : : break;
239 : :
240 : 0 : case OPT_frust_dump_:
241 : : // enable dump and return whether this was successful
242 : 0 : if (arg != nullptr)
243 : : {
244 : 0 : ret = enable_dump (std::string (arg));
245 : : }
246 : : else
247 : : {
248 : : ret = false;
249 : : }
250 : : break;
251 : :
252 : 2 : case OPT_frust_mangling_:
253 : 2 : Compile::Mangler::set_mangling (flag_rust_mangling);
254 : 2 : break;
255 : :
256 : 68 : case OPT_frust_cfg_:
257 : 68 : {
258 : 68 : auto string_arg = std::string (arg);
259 : 68 : ret = handle_cfg_option (string_arg);
260 : 68 : break;
261 : 68 : }
262 : 21 : case OPT_frust_crate_type_:
263 : 21 : options.set_crate_type (flag_rust_crate_type);
264 : 21 : break;
265 : 7 : case OPT_frust_edition_:
266 : 7 : options.set_edition (flag_rust_edition);
267 : 7 : break;
268 : 43 : case OPT_frust_compile_until_:
269 : 43 : options.set_compile_step (flag_rust_compile_until);
270 : 43 : break;
271 : 0 : case OPT_frust_metadata_output_:
272 : 0 : options.set_metadata_output (arg);
273 : 0 : break;
274 : 0 : case OPT_frust_panic_:
275 : 0 : options.set_panic_strategy (flag_rust_panic);
276 : 0 : break;
277 : :
278 : : default:
279 : : break;
280 : : }
281 : :
282 : 39809 : return ret;
283 : : }
284 : :
285 : : bool
286 : 0 : Session::handle_extern_option (std::string &input)
287 : : {
288 : 0 : auto pos = input.find ('=');
289 : 0 : if (std::string::npos == pos)
290 : : return false;
291 : :
292 : 0 : std::string libname = input.substr (0, pos);
293 : 0 : std::string path = input.substr (pos + 1);
294 : :
295 : 0 : extern_crates.insert ({libname, path});
296 : 0 : return true;
297 : 0 : }
298 : :
299 : : bool
300 : 68 : Session::handle_cfg_option (std::string &input)
301 : : {
302 : 68 : std::string key;
303 : 68 : std::string value;
304 : :
305 : : // Refactor this if needed
306 : 68 : if (!parse_cfg_option (input, key, value))
307 : : {
308 : 0 : rust_error_at (
309 : : UNDEF_LOCATION,
310 : : "invalid argument to %<-frust-cfg%>: Accepted formats are "
311 : : "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)");
312 : 0 : return false;
313 : : }
314 : :
315 : 68 : if (value.empty ())
316 : : // rustc does not seem to error on dup key
317 : 132 : options.target_data.insert_key (key);
318 : : else
319 : 6 : options.target_data.insert_key_value_pair (key, value);
320 : :
321 : : return true;
322 : 68 : }
323 : :
324 : : /* Enables a certain dump depending on the name passed in. Returns true if
325 : : * name is valid, false otherwise. */
326 : : bool
327 : 0 : Session::enable_dump (std::string arg)
328 : : {
329 : 0 : if (arg.empty ())
330 : : {
331 : 0 : rust_error_at (
332 : : UNDEF_LOCATION,
333 : : "dump option was not given a name. choose %<lex%>, %<ast-pretty%>, "
334 : : "%<register_plugins%>, %<injection%>, "
335 : : "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
336 : : "%<hir-pretty%>, %<bir%> or %<all%>");
337 : 0 : return false;
338 : : }
339 : :
340 : 0 : if (arg == "all")
341 : : {
342 : 0 : options.enable_all_dump_options ();
343 : : }
344 : 0 : else if (arg == "lex")
345 : : {
346 : 0 : options.enable_dump_option (CompileOptions::LEXER_DUMP);
347 : : }
348 : 0 : else if (arg == "ast-pretty")
349 : : {
350 : 0 : options.enable_dump_option (CompileOptions::AST_DUMP_PRETTY);
351 : : }
352 : 0 : else if (arg == "register_plugins")
353 : : {
354 : 0 : options.enable_dump_option (CompileOptions::REGISTER_PLUGINS_DUMP);
355 : : }
356 : 0 : else if (arg == "injection")
357 : : {
358 : 0 : options.enable_dump_option (CompileOptions::INJECTION_DUMP);
359 : : }
360 : 0 : else if (arg == "expansion")
361 : : {
362 : 0 : options.enable_dump_option (CompileOptions::EXPANSION_DUMP);
363 : : }
364 : 0 : else if (arg == "resolution")
365 : : {
366 : 0 : options.enable_dump_option (CompileOptions::RESOLUTION_DUMP);
367 : : }
368 : 0 : else if (arg == "target_options")
369 : : {
370 : 0 : options.enable_dump_option (CompileOptions::TARGET_OPTION_DUMP);
371 : : }
372 : 0 : else if (arg == "hir")
373 : : {
374 : 0 : options.enable_dump_option (CompileOptions::HIR_DUMP);
375 : : }
376 : 0 : else if (arg == "hir-pretty")
377 : : {
378 : 0 : options.enable_dump_option (CompileOptions::HIR_DUMP_PRETTY);
379 : : }
380 : 0 : else if (arg == "bir")
381 : : {
382 : 0 : options.enable_dump_option (CompileOptions::BIR_DUMP);
383 : : }
384 : : else
385 : : {
386 : 0 : rust_error_at (
387 : : UNDEF_LOCATION,
388 : : "dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, "
389 : : "%<register_plugins%>, %<injection%>, "
390 : : "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, "
391 : : "%<hir-pretty%>, or %<all%>",
392 : : arg.c_str ());
393 : 0 : return false;
394 : : }
395 : : return true;
396 : : }
397 : :
398 : : /* Actual main entry point for front-end. Called from langhook to parse files.
399 : : */
400 : : void
401 : 4403 : Session::handle_input_files (int num_files, const char **files)
402 : : {
403 : 4403 : if (num_files != 1)
404 : 0 : rust_fatal_error (UNDEF_LOCATION,
405 : : "only one file may be specified on the command line");
406 : :
407 : 4403 : const auto &file = files[0];
408 : :
409 : 4403 : rust_debug ("Attempting to parse file: %s", file);
410 : 4403 : compile_crate (file);
411 : 4401 : }
412 : :
413 : : void
414 : 4402 : Session::handle_crate_name (const char *filename,
415 : : const AST::Crate &parsed_crate)
416 : : {
417 : 4402 : auto &mappings = Analysis::Mappings::get ();
418 : 4402 : auto crate_name_found = false;
419 : 4402 : auto error = Error (UNDEF_LOCATION, std::string ());
420 : :
421 : 5150 : for (const auto &attr : parsed_crate.inner_attrs)
422 : : {
423 : 748 : if (attr.get_path () != "crate_name")
424 : 739 : continue;
425 : 10 : if (!attr.has_attr_input ())
426 : : {
427 : 0 : rust_error_at (attr.get_locus (),
428 : : "%<crate_name%> accepts one argument");
429 : 0 : continue;
430 : : }
431 : :
432 : 10 : auto &literal
433 : 10 : = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
434 : 10 : const auto &msg_str = literal.get_literal ().as_string ();
435 : 10 : if (!validate_crate_name (msg_str, error))
436 : : {
437 : 1 : error.locus = attr.get_locus ();
438 : 1 : error.emit ();
439 : 1 : continue;
440 : : }
441 : :
442 : 9 : if (options.crate_name_set_manually && (options.crate_name != msg_str))
443 : : {
444 : 1 : rust_error_at (attr.get_locus (),
445 : : "%<-frust-crate-name%> and %<#[crate_name]%> are "
446 : : "required to match, but %qs does not match %qs",
447 : : options.crate_name.c_str (), msg_str.c_str ());
448 : : }
449 : 9 : crate_name_found = true;
450 : 18 : options.set_crate_name (msg_str);
451 : 10 : }
452 : :
453 : 4402 : options.crate_name_set_manually |= crate_name_found;
454 : 4402 : if (!options.crate_name_set_manually)
455 : : {
456 : 4383 : auto crate_name = infer_crate_name (filename);
457 : 4383 : if (crate_name.empty ())
458 : : {
459 : 0 : rust_error_at (UNDEF_LOCATION, "crate name is empty");
460 : 0 : rust_inform (linemap_position_for_column (line_table, 0),
461 : : "crate name inferred from this file");
462 : 0 : return;
463 : : }
464 : :
465 : 4383 : rust_debug ("inferred crate name: %s", crate_name.c_str ());
466 : 8766 : options.set_crate_name (crate_name);
467 : :
468 : 4383 : if (!validate_crate_name (options.get_crate_name (), error))
469 : : {
470 : 1 : error.emit ();
471 : 1 : rust_inform (linemap_position_for_column (line_table, 0),
472 : : "crate name inferred from this file");
473 : 1 : return;
474 : : }
475 : 4383 : }
476 : :
477 : 4401 : if (saw_errors ())
478 : : return;
479 : :
480 : 4314 : CrateNum crate_num = mappings.get_next_crate_num (options.get_crate_name ());
481 : 4314 : mappings.set_current_crate (crate_num);
482 : 4402 : }
483 : :
484 : : // Parses a single file with filename filename.
485 : : void
486 : 4403 : Session::compile_crate (const char *filename)
487 : : {
488 : 4403 : if (!flag_rust_experimental
489 : 4403 : && !std::getenv ("GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE"))
490 : 0 : rust_fatal_error (
491 : : UNDEF_LOCATION, "%s",
492 : : "gccrs is not yet able to compile Rust code "
493 : : "properly. Most of the errors produced will be the fault of gccrs and "
494 : : "not the crate you are trying to compile. Because of this, please report "
495 : : "errors directly to us instead of opening issues on said crate's "
496 : : "repository.\n\n"
497 : : "Our github repository: "
498 : : "https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: "
499 : : "https://gcc.gnu.org/bugzilla/"
500 : : "buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n"
501 : : "If you understand this, and understand that the binaries produced might "
502 : : "not behave accordingly, you may attempt to use gccrs in an experimental "
503 : : "manner by passing the following flag:\n\n"
504 : : "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by "
505 : : "defining the following environment variable (any value will "
506 : : "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor "
507 : : "cargo-gccrs, this means passing\n\n"
508 : : "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-"
509 : : "use\"\n\nas an environment variable.");
510 : :
511 : 4403 : RAIIFile file_wrap (filename);
512 : 4403 : if (!file_wrap.ok ())
513 : : {
514 : 0 : rust_error_at (UNDEF_LOCATION, "cannot open filename %s: %m", filename);
515 : 0 : return;
516 : : }
517 : :
518 : 4403 : auto last_step = options.get_compile_until ();
519 : :
520 : : // parse file here
521 : : /* create lexer and parser - these are file-specific and so aren't instance
522 : : * variables */
523 : 4403 : tl::optional<std::ofstream &> dump_lex_opt = tl::nullopt;
524 : 4403 : std::ofstream dump_lex_stream;
525 : 4403 : if (options.dump_option_enabled (CompileOptions::LEXER_DUMP))
526 : : {
527 : 0 : dump_lex_stream.open (kLexDumpFile);
528 : 0 : if (dump_lex_stream.fail ())
529 : 0 : rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
530 : : kLexDumpFile);
531 : :
532 : 0 : dump_lex_opt = dump_lex_stream;
533 : : }
534 : :
535 : 4403 : Lexer lex (filename, std::move (file_wrap), linemap, dump_lex_opt);
536 : :
537 : 4403 : if (!lex.input_source_is_valid_utf8 ())
538 : : {
539 : 1 : rust_error_at (UNKNOWN_LOCATION,
540 : : "cannot read %s; stream did not contain valid UTF-8",
541 : : filename);
542 : 1 : return;
543 : : }
544 : :
545 : 4402 : Parser<Lexer> parser (lex);
546 : :
547 : : // generate crate from parser
548 : 4402 : std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate ();
549 : :
550 : : // handle crate name
551 : 4402 : handle_crate_name (filename, *ast_crate.get ());
552 : :
553 : : // dump options except lexer dump
554 : 4402 : if (options.dump_option_enabled (CompileOptions::AST_DUMP_PRETTY))
555 : : {
556 : 0 : dump_ast_pretty (*ast_crate.get ());
557 : : }
558 : 4402 : if (options.dump_option_enabled (CompileOptions::TARGET_OPTION_DUMP))
559 : : {
560 : 0 : options.target_data.dump_target_options ();
561 : : }
562 : :
563 : 4402 : if (saw_errors ())
564 : : return;
565 : :
566 : : // setup the mappings for this AST
567 : 4314 : CrateNum current_crate = mappings.get_current_crate ();
568 : 4314 : AST::Crate &parsed_crate
569 : 4314 : = mappings.insert_ast_crate (std::move (ast_crate), current_crate);
570 : :
571 : : /* basic pipeline:
572 : : * - lex
573 : : * - parse
574 : : * - register plugins (dummy stage for now) - attribute injection? what is
575 : : * this? (attribute injection is injecting attributes specified in command
576 : : * line into crate root)
577 : : * - injection (some lint checks or dummy, register builtin macros, crate
578 : : * injection)
579 : : * - expansion (expands all macros, maybe build test harness, AST
580 : : * validation, maybe macro crate)
581 : : * - resolution (name resolution, type resolution, maybe feature checking,
582 : : * maybe buffered lints)
583 : : * TODO not done */
584 : :
585 : 4314 : rust_debug ("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m");
586 : :
587 : : // If -fsyntax-only was passed, we can just skip the remaining passes.
588 : : // Parsing errors are already emitted in `parse_crate()`
589 : 4314 : if (flag_syntax_only || last_step == CompileOptions::CompileStep::Ast)
590 : : return;
591 : :
592 : : // register plugins pipeline stage
593 : 4290 : register_plugins (parsed_crate);
594 : 4290 : rust_debug ("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m");
595 : 4290 : if (options.dump_option_enabled (CompileOptions::REGISTER_PLUGINS_DUMP))
596 : : {
597 : : // TODO: what do I dump here?
598 : : }
599 : :
600 : : // injection pipeline stage
601 : 4290 : injection (parsed_crate);
602 : 4290 : rust_debug ("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m");
603 : 4290 : if (options.dump_option_enabled (CompileOptions::INJECTION_DUMP))
604 : : {
605 : : // TODO: what do I dump here? injected crate names?
606 : : }
607 : :
608 : 4290 : if (last_step == CompileOptions::CompileStep::AttributeCheck)
609 : : return;
610 : :
611 : 4290 : Analysis::AttributeChecker ().go (parsed_crate);
612 : :
613 : 4290 : if (last_step == CompileOptions::CompileStep::Expansion)
614 : : return;
615 : :
616 : 4290 : AST::CollectLangItems ().go (parsed_crate);
617 : :
618 : 4290 : auto name_resolution_ctx = Resolver2_0::NameResolutionContext ();
619 : : // expansion pipeline stage
620 : :
621 : 4290 : expansion (parsed_crate, name_resolution_ctx);
622 : :
623 : 4290 : rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m");
624 : 4290 : if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP))
625 : : {
626 : : // dump AST with expanded stuff
627 : 0 : rust_debug ("BEGIN POST-EXPANSION AST DUMP");
628 : 0 : dump_ast_pretty (parsed_crate, true);
629 : 0 : rust_debug ("END POST-EXPANSION AST DUMP");
630 : : }
631 : :
632 : : // AST Validation pass
633 : 4290 : if (last_step == CompileOptions::CompileStep::ASTValidation)
634 : : return;
635 : :
636 : 4289 : ASTValidation ().check (parsed_crate);
637 : :
638 : : // feature gating
639 : 4289 : if (last_step == CompileOptions::CompileStep::FeatureGating)
640 : : return;
641 : 4289 : FeatureGate ().check (parsed_crate);
642 : :
643 : 4289 : if (last_step == CompileOptions::CompileStep::NameResolution)
644 : : return;
645 : :
646 : : // resolution pipeline stage
647 : 4286 : if (flag_name_resolution_2_0)
648 : 4286 : Resolver2_0::Late (name_resolution_ctx).go (parsed_crate);
649 : : else
650 : 0 : Resolver::NameResolution::Resolve (parsed_crate);
651 : :
652 : 4285 : if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP))
653 : 0 : dump_name_resolution (name_resolution_ctx);
654 : :
655 : 4285 : if (saw_errors ())
656 : : return;
657 : :
658 : 4140 : if (last_step == CompileOptions::CompileStep::Lowering)
659 : : return;
660 : :
661 : : // lower AST to HIR
662 : 4131 : std::unique_ptr<HIR::Crate> lowered
663 : 4131 : = HIR::ASTLowering::Resolve (parsed_crate);
664 : 4131 : if (saw_errors ())
665 : : return;
666 : :
667 : : // add the mappings to it
668 : 4123 : HIR::Crate &hir = mappings.insert_hir_crate (std::move (lowered));
669 : 4123 : if (options.dump_option_enabled (CompileOptions::HIR_DUMP))
670 : : {
671 : 0 : dump_hir (hir);
672 : : }
673 : 4123 : if (options.dump_option_enabled (CompileOptions::HIR_DUMP_PRETTY))
674 : : {
675 : 0 : dump_hir_pretty (hir);
676 : : }
677 : :
678 : 4123 : if (last_step == CompileOptions::CompileStep::TypeCheck)
679 : : return;
680 : :
681 : : // name resolution is done, we now freeze the name resolver for type checking
682 : 4118 : Resolver2_0::ImmutableNameResolutionContext::init (name_resolution_ctx);
683 : :
684 : : // type resolve
685 : 4118 : Compile::Context *ctx = Compile::Context::get ();
686 : 4118 : Resolver::TypeResolution::Resolve (hir);
687 : :
688 : 4117 : Resolver::TypeCheckContext::get ()->get_variance_analysis_ctx ().solve ();
689 : :
690 : 4117 : if (saw_errors ())
691 : : return;
692 : :
693 : 3956 : Analysis::PatternChecker ().go (hir);
694 : :
695 : 3956 : if (saw_errors ())
696 : : return;
697 : :
698 : 3953 : if (last_step == CompileOptions::CompileStep::Privacy)
699 : : return;
700 : :
701 : : // Various HIR error passes. The privacy pass happens before the unsafe checks
702 : 3953 : Privacy::Resolver::resolve (hir);
703 : 3953 : if (saw_errors ())
704 : : return;
705 : :
706 : 3943 : if (last_step == CompileOptions::CompileStep::Unsafety)
707 : : return;
708 : :
709 : 3942 : HIR::UnsafeChecker ().go (hir);
710 : :
711 : 3942 : if (last_step == CompileOptions::CompileStep::Const)
712 : : return;
713 : :
714 : 3942 : HIR::ConstChecker ().go (hir);
715 : :
716 : 3942 : if (last_step == CompileOptions::CompileStep::BorrowCheck)
717 : : return;
718 : :
719 : 3942 : if (flag_borrowcheck)
720 : : {
721 : 11 : const bool dump_bir
722 : 11 : = options.dump_option_enabled (CompileOptions::DumpOption::BIR_DUMP);
723 : 11 : HIR::BorrowChecker (dump_bir).go (hir);
724 : : }
725 : :
726 : 3942 : if (saw_errors ())
727 : : return;
728 : :
729 : 3906 : if (last_step == CompileOptions::CompileStep::Compilation)
730 : : return;
731 : :
732 : : // do compile to gcc generic
733 : 3904 : Compile::CompileCrate::Compile (hir, ctx);
734 : :
735 : : // we can't do static analysis if there are errors to worry about
736 : 3904 : if (!saw_errors ())
737 : : {
738 : : // lints
739 : 3866 : Analysis::ScanDeadcode::Scan (hir);
740 : 3866 : Analysis::UnusedVariables::Lint (*ctx);
741 : 3866 : Analysis::ReadonlyCheck::Lint (*ctx);
742 : :
743 : : // metadata
744 : 3866 : bool specified_emit_metadata
745 : 3866 : = flag_rust_embed_metadata || options.metadata_output_path_set ();
746 : 3866 : if (!specified_emit_metadata)
747 : : {
748 : 3866 : Metadata::PublicInterface::ExportTo (
749 : 7732 : hir, Metadata::PublicInterface::expected_metadata_filename ());
750 : : }
751 : : else
752 : : {
753 : 0 : if (flag_rust_embed_metadata)
754 : 0 : Metadata::PublicInterface::Export (hir);
755 : 0 : if (options.metadata_output_path_set ())
756 : 0 : Metadata::PublicInterface::ExportTo (
757 : : hir, options.get_metadata_output ());
758 : : }
759 : : }
760 : :
761 : : // pass to GCC middle-end
762 : 3904 : ctx->write_to_backend ();
763 : 9298 : }
764 : :
765 : : void
766 : 4290 : Session::register_plugins (AST::Crate &crate ATTRIBUTE_UNUSED)
767 : : {
768 : 4290 : rust_debug ("ran register_plugins (with no body)");
769 : 4290 : }
770 : :
771 : : // TODO: move somewhere else
772 : : bool
773 : 8578 : contains_name (const AST::AttrVec &attrs, std::string name)
774 : : {
775 : 10048 : for (const auto &attr : attrs)
776 : : {
777 : 1472 : if (attr.get_path () == name)
778 : 8578 : return true;
779 : : }
780 : :
781 : : return false;
782 : : }
783 : :
784 : : void
785 : 4290 : Session::injection (AST::Crate &crate)
786 : : {
787 : 4290 : rust_debug ("started injection");
788 : :
789 : : // lint checks in future maybe?
790 : :
791 : : // register builtin macros
792 : : /* In rustc, builtin macros are divided into 3 categories depending on use -
793 : : * "bang" macros, "attr" macros, and "derive" macros. I think the meanings
794 : : * of these categories should be fairly obvious to anyone who has used rust.
795 : : * Builtin macro list by category: Bang
796 : : * - asm
797 : : * - assert
798 : : * - cfg
799 : : * - column
800 : : * - compile_error
801 : : * - concat_idents
802 : : * - concat
803 : : * - env
804 : : * - file
805 : : * - format_args_nl
806 : : * - format_args
807 : : * - global_asm
808 : : * - include_bytes
809 : : * - include_str
810 : : * - include
811 : : * - line
812 : : * - log_syntax
813 : : * - module_path
814 : : * - option_env
815 : : * - stringify
816 : : * - trace_macros
817 : : * Attr
818 : : * - bench
819 : : * - global_allocator
820 : : * - test
821 : : * - test_case
822 : : * Derive
823 : : * - Clone
824 : : * - Copy
825 : : * - Debug
826 : : * - Default
827 : : * - Eq
828 : : * - Hash
829 : : * - Ord
830 : : * - PartialEq
831 : : * - PartialOrd
832 : : * - RustcDecodable
833 : : * - RustcEncodable
834 : : * rustc also has a "quote" macro that is defined differently and is
835 : : * supposedly not stable so eh. */
836 : : /* TODO: actually implement injection of these macros. In particular, derive
837 : : * macros, cfg, and test should be prioritised since they seem to be used
838 : : * the most. */
839 : :
840 : : // crate injection
841 : 4290 : std::vector<std::string> names;
842 : 4290 : if (contains_name (crate.inner_attrs, "no_core"))
843 : : {
844 : : // no prelude
845 : 2 : injected_crate_name = "";
846 : : }
847 : 4288 : else if (contains_name (crate.inner_attrs, "no_std"))
848 : : {
849 : 0 : names.push_back ("core");
850 : :
851 : 0 : if (!contains_name (crate.inner_attrs, "compiler_builtins"))
852 : : {
853 : 0 : names.push_back ("compiler_builtins");
854 : : }
855 : :
856 : 0 : injected_crate_name = "core";
857 : : }
858 : : else
859 : : {
860 : 4288 : names.push_back ("std");
861 : :
862 : 4288 : injected_crate_name = "std";
863 : : }
864 : :
865 : : // reverse iterate through names to insert crate items in "forward" order at
866 : : // beginning of crate
867 : 8578 : for (auto it = names.rbegin (); it != names.rend (); ++it)
868 : : {
869 : : // create "macro use" attribute for use on extern crate item to enable
870 : : // loading macros from it
871 : 4288 : AST::Attribute attr (AST::SimplePath::from_str (
872 : 4288 : Values::Attributes::MACRO_USE, UNDEF_LOCATION),
873 : 12864 : nullptr);
874 : :
875 : : // create "extern crate" item with the name
876 : 4288 : std::unique_ptr<AST::ExternCrate> extern_crate (
877 : 4288 : new AST::ExternCrate (*it, AST::Visibility::create_error (),
878 : 12864 : {std::move (attr)}, UNKNOWN_LOCATION));
879 : :
880 : : // insert at beginning
881 : : // crate.items.insert (crate.items.begin (), std::move (extern_crate));
882 : 8576 : }
883 : :
884 : : // create use tree path
885 : : // prelude is injected_crate_name
886 : : // FIXME: Once we do want to include the standard library, add the prelude
887 : : // use item
888 : : // std::vector<AST::SimplePathSegment> segments
889 : : // = {AST::SimplePathSegment (injected_crate_name, UNDEF_LOCATION),
890 : : // AST::SimplePathSegment ("prelude", UNDEF_LOCATION),
891 : : // AST::SimplePathSegment ("v1", UNDEF_LOCATION)};
892 : : // // create use tree and decl
893 : : // std::unique_ptr<AST::UseTreeGlob> use_tree (
894 : : // new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
895 : : // AST::SimplePath (std::move (segments)),
896 : : // UNDEF_LOCATION));
897 : : // AST::Attribute prelude_attr (AST::SimplePath::from_str ("prelude_import",
898 : : // UNDEF_LOCATION),
899 : : // nullptr);
900 : : // std::unique_ptr<AST::UseDeclaration> use_decl (
901 : : // new AST::UseDeclaration (std::move (use_tree),
902 : : // AST::Visibility::create_error (),
903 : : // {std::move (prelude_attr)}, UNDEF_LOCATION));
904 : :
905 : : // crate.items.insert (crate.items.begin (), std::move (use_decl));
906 : :
907 : : /* TODO: potentially add checking attribute crate type? I can't figure out
908 : : * what this does currently comment says "Unconditionally collect crate
909 : : * types from attributes to make them used", which presumably refers to
910 : : * checking the linkage info by "crate_type". It also seems to ensure that
911 : : * an invalid crate type is not specified, so maybe just do that. Valid
912 : : * crate types: bin lib dylib staticlib cdylib rlib proc-macro */
913 : :
914 : : // this crate type will have options affecting the metadata ouput
915 : :
916 : 4290 : rust_debug ("finished injection");
917 : 4290 : }
918 : :
919 : : void
920 : 4290 : Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx)
921 : : {
922 : 4290 : rust_debug ("started expansion");
923 : :
924 : : /* rustc has a modification to windows PATH temporarily here, which may end
925 : : * up being required */
926 : :
927 : : // create macro expansion config?
928 : : // if not, would at least have to configure recursion_limit
929 : 4290 : ExpansionCfg cfg;
930 : :
931 : 4290 : auto fixed_point_reached = false;
932 : 4290 : unsigned iterations = 0;
933 : :
934 : : // create extctxt? from parse session, cfg, and resolver?
935 : : /* expand by calling cxtctxt object's monotonic_expander's expand_crate
936 : : * method. */
937 : 4290 : MacroExpander expander (crate, cfg, *this);
938 : 4290 : std::vector<Error> macro_errors;
939 : :
940 : 14212 : while (!fixed_point_reached && iterations < cfg.recursion_limit)
941 : : {
942 : 9996 : CfgStrip ().go (crate);
943 : : // Errors might happen during cfg strip pass
944 : 9996 : bool visitor_dirty = false;
945 : :
946 : 9996 : if (flag_name_resolution_2_0)
947 : : {
948 : 9996 : Resolver2_0::Early early (ctx);
949 : 9996 : early.go (crate);
950 : 9996 : macro_errors = early.get_macro_resolve_errors ();
951 : 9996 : visitor_dirty = early.is_dirty ();
952 : 9996 : }
953 : : else
954 : 0 : Resolver::EarlyNameResolver ().go (crate);
955 : :
956 : 9996 : if (saw_errors ())
957 : : break;
958 : :
959 : 9953 : ExpandVisitor (expander).go (crate);
960 : :
961 : 9953 : fixed_point_reached = !expander.has_changed () && !visitor_dirty;
962 : 9953 : expander.reset_changed_state ();
963 : 9953 : iterations++;
964 : :
965 : 9953 : if (saw_errors ())
966 : : break;
967 : : }
968 : :
969 : : // Fixed point reached: Emit unresolved macros error
970 : 4311 : for (auto &error : macro_errors)
971 : 21 : error.emit ();
972 : :
973 : 4290 : if (iterations == cfg.recursion_limit)
974 : : {
975 : 1 : auto &last_invoc = expander.get_last_invocation ();
976 : 1 : auto &last_def = expander.get_last_definition ();
977 : :
978 : 1 : rust_assert (last_def.has_value () && last_invoc.has_value ());
979 : :
980 : 1 : rich_location range (line_table, last_invoc->get_locus ());
981 : 1 : range.add_range (last_def->get_locus ());
982 : :
983 : 1 : rust_error_at (range, "reached recursion limit");
984 : 1 : }
985 : :
986 : : // handle AST desugaring
987 : 4290 : if (!saw_errors ())
988 : : {
989 : 4208 : AST::ExpressionYeast ().go (crate);
990 : :
991 : 4208 : AST::DesugarApit ().go (crate);
992 : :
993 : : // HACK: we may need a final TopLevel pass
994 : : // however, this should not count towards the recursion limit
995 : : // and we don't need a full Early pass
996 : 4208 : if (flag_name_resolution_2_0)
997 : 4208 : Resolver2_0::TopLevel (ctx).go (crate);
998 : : }
999 : :
1000 : : // error reporting - check unused macros, get missing fragment specifiers
1001 : :
1002 : : // build test harness
1003 : :
1004 : : // ast validation (also with proc macro decls)
1005 : :
1006 : : // maybe create macro crate if not rustdoc
1007 : :
1008 : 4290 : rust_debug ("finished expansion");
1009 : 4290 : }
1010 : :
1011 : : void
1012 : 0 : Session::dump_ast_pretty (AST::Crate &crate, bool expanded) const
1013 : : {
1014 : 0 : std::ofstream out;
1015 : 0 : if (expanded)
1016 : 0 : out.open (kASTPrettyDumpFileExpanded);
1017 : : else
1018 : 0 : out.open (kASTPrettyDumpFile);
1019 : :
1020 : 0 : if (out.fail ())
1021 : : {
1022 : 0 : rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
1023 : : kASTDumpFile);
1024 : 0 : return;
1025 : : }
1026 : :
1027 : 0 : AST::Dump (out).go (crate);
1028 : :
1029 : 0 : out.close ();
1030 : 0 : }
1031 : :
1032 : : void
1033 : 0 : Session::dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const
1034 : : {
1035 : : // YES this is ugly but NO GCC 4.8 does not allow us to make it fancier :(
1036 : 0 : std::string types_content = ctx.types.as_debug_string ();
1037 : 0 : std::ofstream types_stream{kASTtypeResolutionDumpFile};
1038 : 0 : types_stream << types_content;
1039 : :
1040 : 0 : std::string macros_content = ctx.macros.as_debug_string ();
1041 : 0 : std::ofstream macros_stream{kASTmacroResolutionDumpFile};
1042 : 0 : macros_stream << macros_content;
1043 : :
1044 : 0 : std::string labels_content = ctx.labels.as_debug_string ();
1045 : 0 : std::ofstream labels_stream{kASTlabelResolutionDumpFile};
1046 : 0 : labels_stream << labels_content;
1047 : :
1048 : 0 : std::string values_content = ctx.values.as_debug_string ();
1049 : 0 : std::ofstream values_stream{kASTvalueResolutionDumpFile};
1050 : 0 : values_stream << values_content;
1051 : 0 : }
1052 : :
1053 : : void
1054 : 0 : Session::dump_hir (HIR::Crate &crate) const
1055 : : {
1056 : 0 : std::ofstream out;
1057 : 0 : out.open (kHIRDumpFile);
1058 : 0 : if (out.fail ())
1059 : : {
1060 : 0 : rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
1061 : : kHIRDumpFile);
1062 : 0 : return;
1063 : : }
1064 : :
1065 : 0 : out << crate.as_string ();
1066 : 0 : out.close ();
1067 : 0 : }
1068 : :
1069 : : void
1070 : 0 : Session::dump_hir_pretty (HIR::Crate &crate) const
1071 : : {
1072 : 0 : std::ofstream out;
1073 : 0 : out.open (kHIRPrettyDumpFile);
1074 : 0 : if (out.fail ())
1075 : : {
1076 : 0 : rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
1077 : : kHIRPrettyDumpFile);
1078 : 0 : return;
1079 : : }
1080 : :
1081 : 0 : HIR::Dump (out).go (crate);
1082 : 0 : out.close ();
1083 : 0 : }
1084 : :
1085 : : // imports
1086 : :
1087 : : NodeId
1088 : 51 : Session::load_extern_crate (const std::string &crate_name, location_t locus)
1089 : : {
1090 : : // has it already been loaded?
1091 : 51 : if (auto crate_num = mappings.lookup_crate_name (crate_name))
1092 : : {
1093 : 24 : auto resolved_node_id = mappings.crate_num_to_nodeid (*crate_num);
1094 : 24 : rust_assert (resolved_node_id);
1095 : :
1096 : 24 : return *resolved_node_id;
1097 : : }
1098 : :
1099 : 27 : std::string relative_import_path = "";
1100 : 27 : std::string import_name = crate_name;
1101 : :
1102 : : // The path to the extern crate might have been specified by the user using
1103 : : // -frust-extern
1104 : 27 : auto cli_extern_crate = extern_crates.find (crate_name);
1105 : :
1106 : 27 : std::pair<std::unique_ptr<Import::Stream>, std::vector<ProcMacro::Procmacro>>
1107 : 27 : package_result;
1108 : 27 : if (cli_extern_crate != extern_crates.end ())
1109 : : {
1110 : 0 : auto path = cli_extern_crate->second;
1111 : 0 : package_result = Import::try_package_in_directory (path, locus);
1112 : 0 : }
1113 : : else
1114 : : {
1115 : 27 : package_result
1116 : 54 : = Import::open_package (import_name, locus, relative_import_path);
1117 : : }
1118 : :
1119 : 27 : auto stream = std::move (package_result.first);
1120 : 27 : auto proc_macros = std::move (package_result.second);
1121 : :
1122 : 27 : if (stream == NULL // No stream and
1123 : 27 : && proc_macros.empty ()) // no proc macros
1124 : : {
1125 : 3 : rust_error_at (locus, "failed to locate crate %qs", import_name.c_str ());
1126 : 3 : return UNKNOWN_NODEID;
1127 : : }
1128 : :
1129 : 24 : auto extern_crate
1130 : 24 : = stream == nullptr
1131 : 24 : ? Imports::ExternCrate (crate_name,
1132 : 0 : proc_macros) // Import proc macros
1133 : 24 : : Imports::ExternCrate (*stream); // Import from stream
1134 : 24 : if (stream != nullptr)
1135 : : {
1136 : 24 : bool ok = extern_crate.load (locus);
1137 : 24 : if (!ok)
1138 : : {
1139 : 0 : rust_error_at (locus, "failed to load crate metadata");
1140 : 0 : return UNKNOWN_NODEID;
1141 : : }
1142 : : }
1143 : :
1144 : : // ensure the current vs this crate name don't collide
1145 : 24 : const std::string current_crate_name = mappings.get_current_crate_name ();
1146 : 24 : if (current_crate_name.compare (extern_crate.get_crate_name ()) == 0)
1147 : : {
1148 : 0 : rust_error_at (locus, "current crate name %qs collides with this",
1149 : : current_crate_name.c_str ());
1150 : 0 : return UNKNOWN_NODEID;
1151 : : }
1152 : :
1153 : : // setup mappings
1154 : 24 : CrateNum saved_crate_num = mappings.get_current_crate ();
1155 : 24 : CrateNum crate_num
1156 : 24 : = mappings.get_next_crate_num (extern_crate.get_crate_name ());
1157 : 24 : mappings.set_current_crate (crate_num);
1158 : :
1159 : : // then lets parse this as a 2nd crate
1160 : 24 : Lexer lex (extern_crate.get_metadata (), linemap);
1161 : 24 : Parser<Lexer> parser (lex);
1162 : 24 : std::unique_ptr<AST::Crate> metadata_crate = parser.parse_crate ();
1163 : :
1164 : 24 : AST::Crate &parsed_crate
1165 : 24 : = mappings.insert_ast_crate (std::move (metadata_crate), crate_num);
1166 : :
1167 : 24 : std::vector<AttributeProcMacro> attribute_macros;
1168 : 24 : std::vector<CustomDeriveProcMacro> derive_macros;
1169 : 24 : std::vector<BangProcMacro> bang_macros;
1170 : :
1171 : 24 : for (auto ¯o : extern_crate.get_proc_macros ())
1172 : : {
1173 : 0 : switch (macro.tag)
1174 : : {
1175 : 0 : case ProcMacro::CUSTOM_DERIVE:
1176 : 0 : derive_macros.push_back (macro.payload.custom_derive);
1177 : 0 : break;
1178 : 0 : case ProcMacro::ATTR:
1179 : 0 : attribute_macros.push_back (macro.payload.attribute);
1180 : 0 : break;
1181 : 0 : case ProcMacro::BANG:
1182 : 0 : bang_macros.push_back (macro.payload.bang);
1183 : 0 : break;
1184 : 0 : default:
1185 : 0 : gcc_unreachable ();
1186 : : }
1187 : : }
1188 : :
1189 : 24 : mappings.insert_attribute_proc_macros (crate_num, attribute_macros);
1190 : 24 : mappings.insert_bang_proc_macros (crate_num, bang_macros);
1191 : 24 : mappings.insert_derive_proc_macros (crate_num, derive_macros);
1192 : :
1193 : : // if flag_name_resolution_2_0 is enabled
1194 : : // then we perform resolution later
1195 : 24 : if (!flag_name_resolution_2_0)
1196 : : {
1197 : : // name resolve it
1198 : 0 : Resolver::NameResolution::Resolve (parsed_crate);
1199 : : }
1200 : :
1201 : : // always restore the crate_num
1202 : 24 : mappings.set_current_crate (saved_crate_num);
1203 : :
1204 : 24 : return parsed_crate.get_node_id ();
1205 : 126 : }
1206 : : //
1207 : :
1208 : : void
1209 : 0 : TargetOptions::dump_target_options () const
1210 : : {
1211 : 0 : std::ofstream out;
1212 : 0 : out.open (kTargetOptionsDumpFile);
1213 : 0 : if (out.fail ())
1214 : : {
1215 : 0 : rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored",
1216 : : kTargetOptionsDumpFile);
1217 : 0 : return;
1218 : : }
1219 : :
1220 : 0 : if (features.empty ())
1221 : : {
1222 : 0 : out << "No target options available!\n";
1223 : : }
1224 : :
1225 : 0 : for (const auto &pairs : features)
1226 : : {
1227 : 0 : for (const auto &value : pairs.second)
1228 : : {
1229 : 0 : if (value.has_value ())
1230 : 0 : out << pairs.first + ": \"" + value.value () + "\"\n";
1231 : : else
1232 : 0 : out << pairs.first + "\n";
1233 : : }
1234 : : }
1235 : :
1236 : 0 : out.close ();
1237 : 0 : }
1238 : :
1239 : : void
1240 : 0 : TargetOptions::init_derived_values ()
1241 : : {
1242 : : // enable derived values based on target families
1243 : 0 : if (has_key_value_pair ("target_family", "unix"))
1244 : 0 : insert_key ("unix");
1245 : 0 : if (has_key_value_pair ("target_family", "windows"))
1246 : 0 : insert_key ("windows");
1247 : :
1248 : : // implicitly enable features - this should not be required in general
1249 : 0 : if (has_key_value_pair ("target_feature", "aes"))
1250 : 0 : enable_implicit_feature_reqs ("aes");
1251 : 0 : if (has_key_value_pair ("target_feature", "avx"))
1252 : 0 : enable_implicit_feature_reqs ("sse4.2");
1253 : 0 : if (has_key_value_pair ("target_feature", "avx2"))
1254 : 0 : enable_implicit_feature_reqs ("avx");
1255 : 0 : if (has_key_value_pair ("target_feature", "pclmulqdq"))
1256 : 0 : enable_implicit_feature_reqs ("sse2");
1257 : 0 : if (has_key_value_pair ("target_feature", "sha"))
1258 : 0 : enable_implicit_feature_reqs ("sse2");
1259 : 0 : if (has_key_value_pair ("target_feature", "sse2"))
1260 : 0 : enable_implicit_feature_reqs ("sse");
1261 : 0 : if (has_key_value_pair ("target_feature", "sse3"))
1262 : 0 : enable_implicit_feature_reqs ("sse2");
1263 : 0 : if (has_key_value_pair ("target_feature", "sse4.1"))
1264 : 0 : enable_implicit_feature_reqs ("sse3");
1265 : 0 : if (has_key_value_pair ("target_feature", "sse4.2"))
1266 : 0 : enable_implicit_feature_reqs ("sse4.1");
1267 : 0 : if (has_key_value_pair ("target_feature", "ssse3"))
1268 : 0 : enable_implicit_feature_reqs ("sse3");
1269 : 0 : }
1270 : :
1271 : : void
1272 : 0 : TargetOptions::enable_implicit_feature_reqs (std::string feature)
1273 : : {
1274 : 0 : if (feature == "aes")
1275 : 0 : enable_implicit_feature_reqs ("sse2");
1276 : 0 : else if (feature == "avx")
1277 : 0 : enable_implicit_feature_reqs ("sse4.2");
1278 : 0 : else if (feature == "avx2")
1279 : 0 : enable_implicit_feature_reqs ("avx");
1280 : 0 : else if (feature == "fma")
1281 : 0 : enable_implicit_feature_reqs ("avx");
1282 : 0 : else if (feature == "pclmulqdq")
1283 : 0 : enable_implicit_feature_reqs ("sse2");
1284 : 0 : else if (feature == "sha")
1285 : 0 : enable_implicit_feature_reqs ("sse2");
1286 : 0 : else if (feature == "sse2")
1287 : 0 : enable_implicit_feature_reqs ("sse");
1288 : 0 : else if (feature == "sse3")
1289 : 0 : enable_implicit_feature_reqs ("sse2");
1290 : 0 : else if (feature == "sse4.1")
1291 : 0 : enable_implicit_feature_reqs ("sse3");
1292 : 0 : else if (feature == "sse4.2")
1293 : 0 : enable_implicit_feature_reqs ("sse4.1");
1294 : 0 : else if (feature == "ssse3")
1295 : 0 : enable_implicit_feature_reqs ("sse3");
1296 : :
1297 : 0 : if (!has_key_value_pair ("target_feature", feature))
1298 : : {
1299 : 0 : insert_key_value_pair ("target_feature", feature);
1300 : :
1301 : 0 : rust_debug ("had to implicitly enable feature '%s'!", feature.c_str ());
1302 : : }
1303 : 0 : }
1304 : :
1305 : : // NOTEs:
1306 : : /* mrustc compile pipeline:
1307 : : * - target load (pass target spec to parser?)
1308 : : * - parse (convert source to AST)
1309 : : * - load crates (load any explicitly mentioned extern crates [not all of
1310 : : * them])
1311 : : * - expand (AST transformations from attributes and macros, loads remaining
1312 : : * extern crates [std/core and any triggered by macro expansion])
1313 : : * - implicit crates (test harness, allocator crate, panic crate)
1314 : : * - resolve use (annotate every 'use' item with source [supposedly handles
1315 : : * nasty recursion])
1316 : : * - resolve index (generate index of visible items for every module [avoids
1317 : : * recursion in next pass])
1318 : : * - resolve absolute (resolve all paths into either variable names
1319 : : * [types/values] or absolute paths)
1320 : : * - HIR lower (convert modified AST to simpler HIR [both expressions and
1321 : : * module tree])
1322 : : * - resolve type aliases (replace any usages of type aliases with actual
1323 : : * type [except associated types])
1324 : : * - resolve bind (iterate HIR tree and set binding annotations on all
1325 : : * concrete types [avoids path lookups later])
1326 : : * - resolve HIR markings (generate "markings" [e.g. for Copy/Send/Sync/...]
1327 : : * for all types
1328 : : * - sort impls (small pass - sort impls into groups)
1329 : : * - resolve UFCS outer (determine source trait for all top-level <T>::Type
1330 : : * [qualified] paths)
1331 : : * - resolve UFCS paths (do the same, but include for exprs this time. also
1332 : : * normalises results of previous pass [expanding known associated types])
1333 : : * - constant evaluate (evaluate all constants)
1334 : : * - typecheck outer (checks impls are sane)
1335 : : * - typecheck expressions (resolve and check types for all exprs)
1336 : : * - expand HIR annotate (annotate how exprs are used - used for closure
1337 : : * extractions and reborrows)
1338 : : * - expand HIR closures (extract closures into structs implementing Fn*
1339 : : * traits)
1340 : : * - expand HIR vtables (generate vtables for types with dyn dispatch)
1341 : : * - expand HIR calls (converts method and callable calls into explicit
1342 : : * function calls)
1343 : : * - expand HIR reborrows (apply reborrow rules [taking '&mut *v' instead of
1344 : : * 'v'])
1345 : : * - expand HIR erasedtype (replace all erased types 'impl Trait' with the
1346 : : * true type)
1347 : : * - typecheck expressions (validate - double check that previous passes
1348 : : * haven't broke type system rules)
1349 : : * - lower MIR (convert HIR exprs into a control-flow graph [MIR])
1350 : : * - MIR validate (check that the generated MIR is consistent)
1351 : : * - MIR cleanup (perform various transformations on MIR - replace reads of
1352 : : * const items with the item itself; convert casts to unsized types into
1353 : : * 'MakeDst' operations)
1354 : : * - MIR optimise (perform various simple optimisations on the MIR - constant
1355 : : * propagation, dead code elimination, borrow elimination, some inlining)
1356 : : * - MIR validate PO (re-validate the MIR)
1357 : : * - MIR validate full (optionally: perform expensive state-tracking
1358 : : * validation on MIR)
1359 : : * - trans enumerate (enumerate all items needed for code generation,
1360 : : * primarily types used for generics)
1361 : : * - trans auto impls (create magic trait impls as enumerated in previous
1362 : : * pass)
1363 : : * - trans monomorph (generate monomorphised copies of all functions [with
1364 : : * generics replaced with real types])
1365 : : * - MIR optimise inline (run optimisation again, this time with full type
1366 : : * info [primarily for inlining])
1367 : : * - HIR serialise (write out HIR dump [module tree and generic/inline MIR])
1368 : : * - trans codegen (generate final output file: emit C source file and call C
1369 : : * compiler) */
1370 : :
1371 : : /* rustc compile pipeline (basic, in way less detail):
1372 : : * - parse input (parse .rs to AST)
1373 : : * - name resolution, macro expansion, and configuration (process AST
1374 : : * recursively, resolving paths, expanding macros, processing #[cfg] nodes
1375 : : * [i.e. maybe stripping stuff from AST])
1376 : : * - lower to HIR
1377 : : * - type check and other analyses (e.g. privacy checking)
1378 : : * - lower to MIR and post-processing (and do stuff like borrow checking)
1379 : : * - translation to LLVM IR and LLVM optimisations (produce the .o files)
1380 : : * - linking (link together .o files) */
1381 : :
1382 : : /* Pierced-together rustc compile pipeline (from source):
1383 : : * - parse input (parse file to crate)
1384 : : * - register plugins (attributes injection, set various options, register
1385 : : * lints, load plugins)
1386 : : * - expansion/configure and expand (initial 'cfg' processing, 'loading
1387 : : * compiler plugins', syntax expansion, secondary 'cfg' expansion, synthesis
1388 : : * of a test harness if required, injection of any std lib dependency and
1389 : : * prelude, and name resolution) - actually documented inline
1390 : : * - seeming pierced-together order: pre-AST expansion lint checks,
1391 : : * registering builtin macros, crate injection, then expand all macros, then
1392 : : * maybe build test harness, AST validation, maybe create a macro crate (if
1393 : : * not rustdoc), name resolution, complete gated feature checking, add all
1394 : : * buffered lints
1395 : : * - create global context (lower to HIR)
1396 : : * - analysis on global context (HIR optimisations? create MIR?)
1397 : : * - code generation
1398 : : * - link */
1399 : : } // namespace Rust
1400 : :
1401 : : #if CHECKING_P
1402 : : namespace selftest {
1403 : : void
1404 : 1 : rust_crate_name_validation_test (void)
1405 : : {
1406 : 1 : auto error = Rust::Error (UNDEF_LOCATION, std::string ());
1407 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("example", error));
1408 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("abcdefg_1234", error));
1409 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("1", error));
1410 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("クレート", error));
1411 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("Sōkrátēs", error));
1412 : 1 : ASSERT_TRUE (Rust::validate_crate_name ("惊吓", error));
1413 : :
1414 : : // NOTE: - is not allowed in the crate name ...
1415 : :
1416 : 1 : ASSERT_FALSE (Rust::validate_crate_name ("abcdefg-1234", error));
1417 : 1 : ASSERT_FALSE (Rust::validate_crate_name ("a+b", error));
1418 : 1 : ASSERT_FALSE (Rust::validate_crate_name ("/a+b/", error));
1419 : 1 : ASSERT_FALSE (Rust::validate_crate_name ("😸++", error));
1420 : 1 : ASSERT_FALSE (Rust::validate_crate_name ("∀", error));
1421 : :
1422 : : /* Tests for crate name inference */
1423 : 1 : ASSERT_EQ (Rust::infer_crate_name (".rs"), "");
1424 : 1 : ASSERT_EQ (Rust::infer_crate_name ("c.rs"), "c");
1425 : : // NOTE: ... but - is allowed when in the filename
1426 : 1 : ASSERT_EQ (Rust::infer_crate_name ("a-b.rs"), "a_b");
1427 : 1 : ASSERT_EQ (Rust::infer_crate_name ("book.rs.txt"), "book.rs");
1428 : : #if defined(HAVE_DOS_BASED_FILE_SYSTEM)
1429 : : ASSERT_EQ (Rust::infer_crate_name ("a\\c\\a-b.rs"), "a_b");
1430 : : #else
1431 : 1 : ASSERT_EQ (Rust::infer_crate_name ("a/c/a-b.rs"), "a_b");
1432 : : #endif
1433 : 1 : }
1434 : : } // namespace selftest
1435 : : #endif // CHECKING_P
|