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