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