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