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