1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::lint;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
10
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
16
17 use rustc_serialize::json;
18
19 use crate::parse::CrateConfig;
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::RealFileName;
25 use rustc_span::SourceFileHashAlgorithm;
26
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
29
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 };
33 use std::collections::{BTreeMap, BTreeSet};
34 use std::fmt;
35 use std::hash::Hash;
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
39
40 /// The different settings that the `-C strip` flag can have.
41 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
42 pub enum Strip {
43 /// Do not strip at all.
44 None,
45
46 /// Strip debuginfo.
47 Debuginfo,
48
49 /// Strip all symbols.
50 Symbols,
51 }
52
53 /// The different settings that the `-C control-flow-guard` flag can have.
54 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
55 pub enum CFGuard {
56 /// Do not emit Control Flow Guard metadata or checks.
57 Disabled,
58
59 /// Emit Control Flow Guard metadata but no checks.
60 NoChecks,
61
62 /// Emit Control Flow Guard metadata and checks.
63 Checks,
64 }
65
66 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
67 pub enum OptLevel {
68 No, // -O0
69 Less, // -O1
70 Default, // -O2
71 Aggressive, // -O3
72 Size, // -Os
73 SizeMin, // -Oz
74 }
75
76 impl_stable_hash_via_hash!(OptLevel);
77
78 /// This is what the `LtoCli` values get mapped to after resolving defaults and
79 /// and taking other command line options into account.
80 ///
81 /// Note that linker plugin-based LTO is a different mechanism entirely.
82 #[derive(Clone, PartialEq)]
83 pub enum Lto {
84 /// Don't do any LTO whatsoever.
85 No,
86
87 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
88 Thin,
89
90 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
91 /// only relevant if multiple CGUs are used.
92 ThinLocal,
93
94 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
95 Fat,
96 }
97
98 /// The different settings that the `-C lto` flag can have.
99 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
100 pub enum LtoCli {
101 /// `-C lto=no`
102 No,
103 /// `-C lto=yes`
104 Yes,
105 /// `-C lto`
106 NoParam,
107 /// `-C lto=thin`
108 Thin,
109 /// `-C lto=fat`
110 Fat,
111 /// No `-C lto` flag passed
112 Unspecified,
113 }
114
115 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
116 /// document highlighting each span of every statement (including terminators). `Terminator` and
117 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
118 /// computed span for the block, representing the entire range, covering the block's terminator and
119 /// all of its statements.
120 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
121 pub enum MirSpanview {
122 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
123 Statement,
124 /// `-Z dump_mir_spanview=terminator`
125 Terminator,
126 /// `-Z dump_mir_spanview=block`
127 Block,
128 }
129
130 /// The different settings that the `-Z instrument-coverage` flag can have.
131 ///
132 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
133 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
134 /// and higher). Nevertheless, there are many variables, depending on options
135 /// selected, code structure, and enabled attributes. If errors are encountered,
136 /// either while compiling or when generating `llvm-cov show` reports, consider
137 /// lowering the optimization level, including or excluding `-C link-dead-code`,
138 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
139 /// instrument-coverage=except-unused-generics`.
140 ///
141 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
142 /// coverage map, it will not attempt to generate synthetic functions for unused
143 /// (and not code-generated) functions (whether they are generic or not). As a
144 /// result, non-codegenned functions will not be included in the coverage map,
145 /// and will not appear, as covered or uncovered, in coverage reports.
146 ///
147 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
148 /// unless the function has type parameters.
149 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
150 pub enum InstrumentCoverage {
151 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
152 All,
153 /// `-Z instrument-coverage=except-unused-generics`
154 ExceptUnusedGenerics,
155 /// `-Z instrument-coverage=except-unused-functions`
156 ExceptUnusedFunctions,
157 /// `-Z instrument-coverage=off` (or `no`, etc.)
158 Off,
159 }
160
161 #[derive(Clone, PartialEq, Hash, Debug)]
162 pub enum LinkerPluginLto {
163 LinkerPlugin(PathBuf),
164 LinkerPluginAuto,
165 Disabled,
166 }
167
168 /// Used with `-Z assert-incr-state`.
169 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
170 pub enum IncrementalStateAssertion {
171 /// Found and loaded an existing session directory.
172 ///
173 /// Note that this says nothing about whether any particular query
174 /// will be found to be red or green.
175 Loaded,
176 /// Did not load an existing session directory.
177 NotLoaded,
178 }
179
180 impl LinkerPluginLto {
enabled(&self) -> bool181 pub fn enabled(&self) -> bool {
182 match *self {
183 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
184 LinkerPluginLto::Disabled => false,
185 }
186 }
187 }
188
189 /// The different settings that can be enabled via the `-Z location-detail` flag.
190 #[derive(Clone, PartialEq, Hash, Debug)]
191 pub struct LocationDetail {
192 pub file: bool,
193 pub line: bool,
194 pub column: bool,
195 }
196
197 impl LocationDetail {
all() -> Self198 pub fn all() -> Self {
199 Self { file: true, line: true, column: true }
200 }
201 }
202
203 #[derive(Clone, PartialEq, Hash, Debug)]
204 pub enum SwitchWithOptPath {
205 Enabled(Option<PathBuf>),
206 Disabled,
207 }
208
209 impl SwitchWithOptPath {
enabled(&self) -> bool210 pub fn enabled(&self) -> bool {
211 match *self {
212 SwitchWithOptPath::Enabled(_) => true,
213 SwitchWithOptPath::Disabled => false,
214 }
215 }
216 }
217
218 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
219 #[derive(Encodable, Decodable)]
220 pub enum SymbolManglingVersion {
221 Legacy,
222 V0,
223 }
224
225 impl_stable_hash_via_hash!(SymbolManglingVersion);
226
227 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
228 pub enum DebugInfo {
229 None,
230 Limited,
231 Full,
232 }
233
234 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
235 #[derive(Encodable, Decodable)]
236 pub enum OutputType {
237 Bitcode,
238 Assembly,
239 LlvmAssembly,
240 Mir,
241 Metadata,
242 Object,
243 Exe,
244 DepInfo,
245 }
246
247 impl_stable_hash_via_hash!(OutputType);
248
249 impl OutputType {
is_compatible_with_codegen_units_and_single_output_file(&self) -> bool250 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
251 match *self {
252 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
253 OutputType::Bitcode
254 | OutputType::Assembly
255 | OutputType::LlvmAssembly
256 | OutputType::Mir
257 | OutputType::Object => false,
258 }
259 }
260
shorthand(&self) -> &'static str261 fn shorthand(&self) -> &'static str {
262 match *self {
263 OutputType::Bitcode => "llvm-bc",
264 OutputType::Assembly => "asm",
265 OutputType::LlvmAssembly => "llvm-ir",
266 OutputType::Mir => "mir",
267 OutputType::Object => "obj",
268 OutputType::Metadata => "metadata",
269 OutputType::Exe => "link",
270 OutputType::DepInfo => "dep-info",
271 }
272 }
273
from_shorthand(shorthand: &str) -> Option<Self>274 fn from_shorthand(shorthand: &str) -> Option<Self> {
275 Some(match shorthand {
276 "asm" => OutputType::Assembly,
277 "llvm-ir" => OutputType::LlvmAssembly,
278 "mir" => OutputType::Mir,
279 "llvm-bc" => OutputType::Bitcode,
280 "obj" => OutputType::Object,
281 "metadata" => OutputType::Metadata,
282 "link" => OutputType::Exe,
283 "dep-info" => OutputType::DepInfo,
284 _ => return None,
285 })
286 }
287
shorthands_display() -> String288 fn shorthands_display() -> String {
289 format!(
290 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
291 OutputType::Bitcode.shorthand(),
292 OutputType::Assembly.shorthand(),
293 OutputType::LlvmAssembly.shorthand(),
294 OutputType::Mir.shorthand(),
295 OutputType::Object.shorthand(),
296 OutputType::Metadata.shorthand(),
297 OutputType::Exe.shorthand(),
298 OutputType::DepInfo.shorthand(),
299 )
300 }
301
extension(&self) -> &'static str302 pub fn extension(&self) -> &'static str {
303 match *self {
304 OutputType::Bitcode => "bc",
305 OutputType::Assembly => "s",
306 OutputType::LlvmAssembly => "ll",
307 OutputType::Mir => "mir",
308 OutputType::Object => "o",
309 OutputType::Metadata => "rmeta",
310 OutputType::DepInfo => "d",
311 OutputType::Exe => "",
312 }
313 }
314 }
315
316 /// The type of diagnostics output to generate.
317 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
318 pub enum ErrorOutputType {
319 /// Output meant for the consumption of humans.
320 HumanReadable(HumanReadableErrorType),
321 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
322 Json {
323 /// Render the JSON in a human readable way (with indents and newlines).
324 pretty: bool,
325 /// The JSON output includes a `rendered` field that includes the rendered
326 /// human output.
327 json_rendered: HumanReadableErrorType,
328 },
329 }
330
331 impl Default for ErrorOutputType {
default() -> Self332 fn default() -> Self {
333 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
334 }
335 }
336
337 /// Parameter to control path trimming.
338 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
339 pub enum TrimmedDefPaths {
340 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
341 #[default]
342 Never,
343 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
344 Always,
345 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
346 GoodPath,
347 }
348
349 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
350 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
351 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
352 /// should only depend on the output types, not the paths they're written to.
353 #[derive(Clone, Debug, Hash)]
354 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
355
356 impl OutputTypes {
new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes357 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
358 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
359 }
360
get(&self, key: &OutputType) -> Option<&Option<PathBuf>>361 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
362 self.0.get(key)
363 }
364
contains_key(&self, key: &OutputType) -> bool365 pub fn contains_key(&self, key: &OutputType) -> bool {
366 self.0.contains_key(key)
367 }
368
keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>>369 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
370 self.0.keys()
371 }
372
values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>>373 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
374 self.0.values()
375 }
376
len(&self) -> usize377 pub fn len(&self) -> usize {
378 self.0.len()
379 }
380
381 // Returns `true` if any of the output types require codegen or linking.
should_codegen(&self) -> bool382 pub fn should_codegen(&self) -> bool {
383 self.0.keys().any(|k| match *k {
384 OutputType::Bitcode
385 | OutputType::Assembly
386 | OutputType::LlvmAssembly
387 | OutputType::Mir
388 | OutputType::Object
389 | OutputType::Exe => true,
390 OutputType::Metadata | OutputType::DepInfo => false,
391 })
392 }
393
394 // Returns `true` if any of the output types require linking.
should_link(&self) -> bool395 pub fn should_link(&self) -> bool {
396 self.0.keys().any(|k| match *k {
397 OutputType::Bitcode
398 | OutputType::Assembly
399 | OutputType::LlvmAssembly
400 | OutputType::Mir
401 | OutputType::Metadata
402 | OutputType::Object
403 | OutputType::DepInfo => false,
404 OutputType::Exe => true,
405 })
406 }
407 }
408
409 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
410 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
411 /// would break dependency tracking for command-line arguments.
412 #[derive(Clone)]
413 pub struct Externs(BTreeMap<String, ExternEntry>);
414
415 #[derive(Clone)]
416 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
417
418 #[derive(Clone, Debug)]
419 pub struct ExternEntry {
420 pub location: ExternLocation,
421 /// Indicates this is a "private" dependency for the
422 /// `exported_private_dependencies` lint.
423 ///
424 /// This can be set with the `priv` option like
425 /// `--extern priv:name=foo.rlib`.
426 pub is_private_dep: bool,
427 /// Add the extern entry to the extern prelude.
428 ///
429 /// This can be disabled with the `noprelude` option like
430 /// `--extern noprelude:name`.
431 pub add_prelude: bool,
432 }
433
434 #[derive(Clone, Debug)]
435 pub enum ExternLocation {
436 /// Indicates to look for the library in the search paths.
437 ///
438 /// Added via `--extern name`.
439 FoundInLibrarySearchDirectories,
440 /// The locations where this extern entry must be found.
441 ///
442 /// The `CrateLoader` is responsible for loading these and figuring out
443 /// which one to use.
444 ///
445 /// Added via `--extern prelude_name=some_file.rlib`
446 ExactPaths(BTreeSet<CanonicalizedPath>),
447 }
448
449 /// Supplied source location of a dependency - for example in a build specification
450 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
451 /// a file and line, then the build system can specify that. On the other hand, it may
452 /// make more sense to have an arbitrary raw string.
453 #[derive(Clone, PartialEq)]
454 pub enum ExternDepSpec {
455 /// Raw string
456 Raw(String),
457 /// Raw data in json format
458 Json(json::Json),
459 }
460
461 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
from(from: &'a ExternDepSpec) -> Self462 fn from(from: &'a ExternDepSpec) -> Self {
463 match from {
464 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
465 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
466 }
467 }
468 }
469
470 impl Externs {
471 /// Used for testing.
new(data: BTreeMap<String, ExternEntry>) -> Externs472 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
473 Externs(data)
474 }
475
get(&self, key: &str) -> Option<&ExternEntry>476 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
477 self.0.get(key)
478 }
479
iter(&self) -> BTreeMapIter<'_, String, ExternEntry>480 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
481 self.0.iter()
482 }
483
len(&self) -> usize484 pub fn len(&self) -> usize {
485 self.0.len()
486 }
487 }
488
489 impl ExternEntry {
new(location: ExternLocation) -> ExternEntry490 fn new(location: ExternLocation) -> ExternEntry {
491 ExternEntry { location, is_private_dep: false, add_prelude: false }
492 }
493
files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>>494 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
495 match &self.location {
496 ExternLocation::ExactPaths(set) => Some(set.iter()),
497 _ => None,
498 }
499 }
500 }
501
502 impl ExternDepSpecs {
new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs503 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
504 ExternDepSpecs(data)
505 }
506
get(&self, key: &str) -> Option<&ExternDepSpec>507 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
508 self.0.get(key)
509 }
510 }
511
512 impl fmt::Display for ExternDepSpec {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result513 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
514 match self {
515 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
516 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
517 }
518 }
519 }
520
521 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
522 pub enum PrintRequest {
523 FileNames,
524 Sysroot,
525 TargetLibdir,
526 CrateName,
527 Cfg,
528 TargetList,
529 TargetCPUs,
530 TargetFeatures,
531 RelocationModels,
532 CodeModels,
533 TlsModels,
534 TargetSpec,
535 NativeStaticLibs,
536 StackProtectorStrategies,
537 }
538
539 #[derive(Copy, Clone)]
540 pub enum BorrowckMode {
541 Mir,
542 Migrate,
543 }
544
545 impl BorrowckMode {
546 /// Returns whether we should run the MIR-based borrow check, but also fall back
547 /// on the AST borrow check if the MIR-based one errors.
migrate(self) -> bool548 pub fn migrate(self) -> bool {
549 match self {
550 BorrowckMode::Mir => false,
551 BorrowckMode::Migrate => true,
552 }
553 }
554 }
555
556 pub enum Input {
557 /// Load source code from a file.
558 File(PathBuf),
559 /// Load source code from a string.
560 Str {
561 /// A string that is shown in place of a filename.
562 name: FileName,
563 /// An anonymous string containing the source code.
564 input: String,
565 },
566 }
567
568 impl Input {
filestem(&self) -> &str569 pub fn filestem(&self) -> &str {
570 match *self {
571 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
572 Input::Str { .. } => "rust_out",
573 }
574 }
575
source_name(&self) -> FileName576 pub fn source_name(&self) -> FileName {
577 match *self {
578 Input::File(ref ifile) => ifile.clone().into(),
579 Input::Str { ref name, .. } => name.clone(),
580 }
581 }
582 }
583
584 #[derive(Clone, Hash, Debug)]
585 pub struct OutputFilenames {
586 pub out_directory: PathBuf,
587 filestem: String,
588 pub single_output_file: Option<PathBuf>,
589 pub temps_directory: Option<PathBuf>,
590 pub outputs: OutputTypes,
591 }
592
593 impl_stable_hash_via_hash!(OutputFilenames);
594
595 pub const RLINK_EXT: &str = "rlink";
596 pub const RUST_CGU_EXT: &str = "rcgu";
597 pub const DWARF_OBJECT_EXT: &str = "dwo";
598
599 impl OutputFilenames {
new( out_directory: PathBuf, out_filestem: String, single_output_file: Option<PathBuf>, temps_directory: Option<PathBuf>, extra: String, outputs: OutputTypes, ) -> Self600 pub fn new(
601 out_directory: PathBuf,
602 out_filestem: String,
603 single_output_file: Option<PathBuf>,
604 temps_directory: Option<PathBuf>,
605 extra: String,
606 outputs: OutputTypes,
607 ) -> Self {
608 OutputFilenames {
609 out_directory,
610 single_output_file,
611 temps_directory,
612 outputs,
613 filestem: format!("{}{}", out_filestem, extra),
614 }
615 }
616
path(&self, flavor: OutputType) -> PathBuf617 pub fn path(&self, flavor: OutputType) -> PathBuf {
618 self.outputs
619 .get(&flavor)
620 .and_then(|p| p.to_owned())
621 .or_else(|| self.single_output_file.clone())
622 .unwrap_or_else(|| self.output_path(flavor))
623 }
624
625 /// Gets the output path where a compilation artifact of the given type
626 /// should be placed on disk.
output_path(&self, flavor: OutputType) -> PathBuf627 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
628 let extension = flavor.extension();
629 self.with_directory_and_extension(&self.out_directory, &extension)
630 }
631
632 /// Gets the path where a compilation artifact of the given type for the
633 /// given codegen unit should be placed on disk. If codegen_unit_name is
634 /// None, a path distinct from those of any codegen unit will be generated.
temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf635 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
636 let extension = flavor.extension();
637 self.temp_path_ext(extension, codegen_unit_name)
638 }
639
640 /// Like `temp_path`, but specifically for dwarf objects.
temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf641 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
642 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
643 }
644
645 /// Like `temp_path`, but also supports things where there is no corresponding
646 /// OutputType, like noopt-bitcode or lto-bitcode.
temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf647 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
648 let mut extension = String::new();
649
650 if let Some(codegen_unit_name) = codegen_unit_name {
651 extension.push_str(codegen_unit_name);
652 }
653
654 if !ext.is_empty() {
655 if !extension.is_empty() {
656 extension.push('.');
657 extension.push_str(RUST_CGU_EXT);
658 extension.push('.');
659 }
660
661 extension.push_str(ext);
662 }
663
664 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
665
666 self.with_directory_and_extension(&temps_directory, &extension)
667 }
668
with_extension(&self, extension: &str) -> PathBuf669 pub fn with_extension(&self, extension: &str) -> PathBuf {
670 self.with_directory_and_extension(&self.out_directory, extension)
671 }
672
with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf673 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
674 let mut path = directory.join(&self.filestem);
675 path.set_extension(extension);
676 path
677 }
678
679 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
680 /// mode is being used, which is the logic that this function is intended to encapsulate.
split_dwarf_path( &self, split_debuginfo_kind: SplitDebuginfo, cgu_name: Option<&str>, ) -> Option<PathBuf>681 pub fn split_dwarf_path(
682 &self,
683 split_debuginfo_kind: SplitDebuginfo,
684 cgu_name: Option<&str>,
685 ) -> Option<PathBuf> {
686 let obj_out = self.temp_path(OutputType::Object, cgu_name);
687 let dwo_out = self.temp_path_dwo(cgu_name);
688 match split_debuginfo_kind {
689 SplitDebuginfo::Off => None,
690 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
691 // (pointing at the path which is being determined here). Use the path to the current
692 // object file.
693 SplitDebuginfo::Packed => Some(obj_out),
694 // Split mode emits the DWARF into a different file, use that path.
695 SplitDebuginfo::Unpacked => Some(dwo_out),
696 }
697 }
698 }
699
host_triple() -> &'static str700 pub fn host_triple() -> &'static str {
701 // Get the host triple out of the build environment. This ensures that our
702 // idea of the host triple is the same as for the set of libraries we've
703 // actually built. We can't just take LLVM's host triple because they
704 // normalize all ix86 architectures to i386.
705 //
706 // Instead of grabbing the host triple (for the current host), we grab (at
707 // compile time) the target triple that this rustc is built with and
708 // calling that (at runtime) the host triple.
709 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
710 }
711
712 impl Default for Options {
default() -> Options713 fn default() -> Options {
714 Options {
715 assert_incr_state: None,
716 crate_types: Vec::new(),
717 optimize: OptLevel::No,
718 debuginfo: DebugInfo::None,
719 lint_opts: Vec::new(),
720 lint_cap: None,
721 describe_lints: false,
722 output_types: OutputTypes(BTreeMap::new()),
723 search_paths: vec![],
724 maybe_sysroot: None,
725 target_triple: TargetTriple::from_triple(host_triple()),
726 test: false,
727 incremental: None,
728 debugging_opts: Default::default(),
729 prints: Vec::new(),
730 borrowck_mode: BorrowckMode::Migrate,
731 cg: Default::default(),
732 error_format: ErrorOutputType::default(),
733 externs: Externs(BTreeMap::new()),
734 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
735 crate_name: None,
736 alt_std_name: None,
737 libs: Vec::new(),
738 unstable_features: UnstableFeatures::Disallow,
739 debug_assertions: true,
740 actually_rustdoc: false,
741 trimmed_def_paths: TrimmedDefPaths::default(),
742 cli_forced_codegen_units: None,
743 cli_forced_thinlto_off: false,
744 remap_path_prefix: Vec::new(),
745 real_rust_source_base_dir: None,
746 edition: DEFAULT_EDITION,
747 json_artifact_notifications: false,
748 json_unused_externs: false,
749 pretty: None,
750 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
751 }
752 }
753 }
754
755 impl Options {
756 /// Returns `true` if there is a reason to build the dep graph.
build_dep_graph(&self) -> bool757 pub fn build_dep_graph(&self) -> bool {
758 self.incremental.is_some()
759 || self.debugging_opts.dump_dep_graph
760 || self.debugging_opts.query_dep_graph
761 }
762
file_path_mapping(&self) -> FilePathMapping763 pub fn file_path_mapping(&self) -> FilePathMapping {
764 FilePathMapping::new(self.remap_path_prefix.clone())
765 }
766
767 /// Returns `true` if there will be an output file generated.
will_create_output_file(&self) -> bool768 pub fn will_create_output_file(&self) -> bool {
769 !self.debugging_opts.parse_only && // The file is just being parsed
770 !self.debugging_opts.ls // The file is just being queried
771 }
772
773 #[inline]
share_generics(&self) -> bool774 pub fn share_generics(&self) -> bool {
775 match self.debugging_opts.share_generics {
776 Some(setting) => setting,
777 None => match self.optimize {
778 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
779 OptLevel::Default | OptLevel::Aggressive => false,
780 },
781 }
782 }
783 }
784
785 impl DebuggingOptions {
diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags786 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
787 HandlerFlags {
788 can_emit_warnings,
789 treat_err_as_bug: self.treat_err_as_bug,
790 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
791 report_delayed_bugs: self.report_delayed_bugs,
792 macro_backtrace: self.macro_backtrace,
793 deduplicate_diagnostics: self.deduplicate_diagnostics,
794 }
795 }
796
get_symbol_mangling_version(&self) -> SymbolManglingVersion797 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
798 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
799 }
800 }
801
802 // The type of entry function, so users can have their own entry functions
803 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
804 pub enum EntryFnType {
805 Main,
806 Start,
807 }
808
809 impl_stable_hash_via_hash!(EntryFnType);
810
811 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
812 pub enum CrateType {
813 Executable,
814 Dylib,
815 Rlib,
816 Staticlib,
817 Cdylib,
818 ProcMacro,
819 }
820
821 impl_stable_hash_via_hash!(CrateType);
822
823 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
824 pub enum Passes {
825 Some(Vec<String>),
826 All,
827 }
828
829 impl Passes {
is_empty(&self) -> bool830 pub fn is_empty(&self) -> bool {
831 match *self {
832 Passes::Some(ref v) => v.is_empty(),
833 Passes::All => false,
834 }
835 }
836 }
837
default_lib_output() -> CrateType838 pub const fn default_lib_output() -> CrateType {
839 CrateType::Rlib
840 }
841
default_configuration(sess: &Session) -> CrateConfig842 fn default_configuration(sess: &Session) -> CrateConfig {
843 let end = &sess.target.endian;
844 let arch = &sess.target.arch;
845 let wordsz = sess.target.pointer_width.to_string();
846 let os = &sess.target.os;
847 let env = &sess.target.env;
848 let abi = &sess.target.abi;
849 let vendor = &sess.target.vendor;
850 let min_atomic_width = sess.target.min_atomic_width();
851 let max_atomic_width = sess.target.max_atomic_width();
852 let atomic_cas = sess.target.atomic_cas;
853 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
854 sess.fatal(&err);
855 });
856
857 let mut ret = FxHashSet::default();
858 ret.reserve(7); // the minimum number of insertions
859 // Target bindings.
860 ret.insert((sym::target_os, Some(Symbol::intern(os))));
861 for fam in &sess.target.families {
862 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
863 if fam == "windows" {
864 ret.insert((sym::windows, None));
865 } else if fam == "unix" {
866 ret.insert((sym::unix, None));
867 }
868 }
869 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
870 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
871 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
872 ret.insert((sym::target_env, Some(Symbol::intern(env))));
873 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
874 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
875 if sess.target.has_elf_tls {
876 ret.insert((sym::target_thread_local, None));
877 }
878 for (i, align) in [
879 (8, layout.i8_align.abi),
880 (16, layout.i16_align.abi),
881 (32, layout.i32_align.abi),
882 (64, layout.i64_align.abi),
883 (128, layout.i128_align.abi),
884 ] {
885 if i >= min_atomic_width && i <= max_atomic_width {
886 let mut insert_atomic = |s, align: Align| {
887 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
888 if atomic_cas {
889 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
890 }
891 if align.bits() == i {
892 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
893 }
894 };
895 let s = i.to_string();
896 insert_atomic(&s, align);
897 if s == wordsz {
898 insert_atomic("ptr", layout.pointer_align.abi);
899 }
900 }
901 }
902
903 let panic_strategy = sess.panic_strategy();
904 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
905
906 for s in sess.opts.debugging_opts.sanitizer {
907 let symbol = Symbol::intern(&s.to_string());
908 ret.insert((sym::sanitize, Some(symbol)));
909 }
910
911 if sess.opts.debug_assertions {
912 ret.insert((sym::debug_assertions, None));
913 }
914 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
915 ret.insert((sym::proc_macro, None));
916 }
917 ret
918 }
919
920 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
921 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
922 /// but the symbol interner is not yet set up then, so we must convert it later.
to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig923 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
924 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
925 }
926
build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig927 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
928 // Combine the configuration requested by the session (command line) with
929 // some default and generated configuration items.
930 let default_cfg = default_configuration(sess);
931 // If the user wants a test runner, then add the test cfg.
932 if sess.opts.test {
933 user_cfg.insert((sym::test, None));
934 }
935 user_cfg.extend(default_cfg.iter().cloned());
936 user_cfg
937 }
938
build_target_config( opts: &Options, target_override: Option<Target>, sysroot: &Path, ) -> Target939 pub(super) fn build_target_config(
940 opts: &Options,
941 target_override: Option<Target>,
942 sysroot: &Path,
943 ) -> Target {
944 let target_result = target_override.map_or_else(
945 || Target::search(&opts.target_triple, sysroot),
946 |t| Ok((t, TargetWarnings::empty())),
947 );
948 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
949 early_error(
950 opts.error_format,
951 &format!(
952 "Error loading target specification: {}. \
953 Run `rustc --print target-list` for a list of built-in targets",
954 e
955 ),
956 )
957 });
958 for warning in target_warnings.warning_messages() {
959 early_warn(opts.error_format, &warning)
960 }
961
962 if !matches!(target.pointer_width, 16 | 32 | 64) {
963 early_error(
964 opts.error_format,
965 &format!(
966 "target specification was invalid: \
967 unrecognized target-pointer-width {}",
968 target.pointer_width
969 ),
970 )
971 }
972
973 target
974 }
975
976 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
977 pub enum OptionStability {
978 Stable,
979 Unstable,
980 }
981
982 pub struct RustcOptGroup {
983 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
984 pub name: &'static str,
985 pub stability: OptionStability,
986 }
987
988 impl RustcOptGroup {
is_stable(&self) -> bool989 pub fn is_stable(&self) -> bool {
990 self.stability == OptionStability::Stable
991 }
992
stable<F>(name: &'static str, f: F) -> RustcOptGroup where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,993 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
994 where
995 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
996 {
997 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
998 }
999
unstable<F>(name: &'static str, f: F) -> RustcOptGroup where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1000 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1001 where
1002 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1003 {
1004 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1005 }
1006 }
1007
1008 // The `opt` local module holds wrappers around the `getopts` API that
1009 // adds extra rustc-specific metadata to each option; such metadata
1010 // is exposed by . The public
1011 // functions below ending with `_u` are the functions that return
1012 // *unstable* options, i.e., options that are only enabled when the
1013 // user also passes the `-Z unstable-options` debugging flag.
1014 mod opt {
1015 // The `fn flag*` etc below are written so that we can use them
1016 // in the future; do not warn about them not being used right now.
1017 #![allow(dead_code)]
1018
1019 use super::RustcOptGroup;
1020
1021 pub type R = RustcOptGroup;
1022 pub type S = &'static str;
1023
stable<F>(name: S, f: F) -> R where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1024 fn stable<F>(name: S, f: F) -> R
1025 where
1026 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1027 {
1028 RustcOptGroup::stable(name, f)
1029 }
1030
unstable<F>(name: S, f: F) -> R where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1031 fn unstable<F>(name: S, f: F) -> R
1032 where
1033 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1034 {
1035 RustcOptGroup::unstable(name, f)
1036 }
1037
longer(a: S, b: S) -> S1038 fn longer(a: S, b: S) -> S {
1039 if a.len() > b.len() { a } else { b }
1040 }
1041
opt_s(a: S, b: S, c: S, d: S) -> R1042 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1043 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1044 }
multi_s(a: S, b: S, c: S, d: S) -> R1045 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1046 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1047 }
flag_s(a: S, b: S, c: S) -> R1048 pub fn flag_s(a: S, b: S, c: S) -> R {
1049 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1050 }
flagmulti_s(a: S, b: S, c: S) -> R1051 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1052 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1053 }
1054
opt(a: S, b: S, c: S, d: S) -> R1055 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1056 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1057 }
multi(a: S, b: S, c: S, d: S) -> R1058 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1059 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1060 }
1061 }
1062
1063 /// Returns the "short" subset of the rustc command line options,
1064 /// including metadata for each option, such as whether the option is
1065 /// part of the stable long-term interface for rustc.
rustc_short_optgroups() -> Vec<RustcOptGroup>1066 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1067 vec![
1068 opt::flag_s("h", "help", "Display this message"),
1069 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1070 opt::multi_s(
1071 "L",
1072 "",
1073 "Add a directory to the library search path. The
1074 optional KIND can be one of dependency, crate, native,
1075 framework, or all (the default).",
1076 "[KIND=]PATH",
1077 ),
1078 opt::multi_s(
1079 "l",
1080 "",
1081 "Link the generated crate(s) to the specified native
1082 library NAME. The optional KIND can be one of
1083 static, framework, or dylib (the default).
1084 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1085 may be specified each with a prefix of either '+' to
1086 enable or '-' to disable.",
1087 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1088 ),
1089 make_crate_type_option(),
1090 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1091 opt::opt_s(
1092 "",
1093 "edition",
1094 "Specify which edition of the compiler to use when compiling code.",
1095 EDITION_NAME_LIST,
1096 ),
1097 opt::multi_s(
1098 "",
1099 "emit",
1100 "Comma separated list of types of output for \
1101 the compiler to emit",
1102 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1103 ),
1104 opt::multi_s(
1105 "",
1106 "print",
1107 "Compiler information to print on stdout",
1108 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1109 target-cpus|target-features|relocation-models|code-models|\
1110 tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
1111 ),
1112 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1113 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1114 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1115 opt::opt_s(
1116 "",
1117 "out-dir",
1118 "Write output to compiler-chosen filename \
1119 in <dir>",
1120 "DIR",
1121 ),
1122 opt::opt_s(
1123 "",
1124 "explain",
1125 "Provide a detailed explanation of an error \
1126 message",
1127 "OPT",
1128 ),
1129 opt::flag_s("", "test", "Build a test harness"),
1130 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1131 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1132 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1133 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1134 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1135 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1136 opt::multi_s(
1137 "",
1138 "cap-lints",
1139 "Set the most restrictive lint level. \
1140 More restrictive lints are capped at this \
1141 level",
1142 "LEVEL",
1143 ),
1144 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1145 opt::flag_s("V", "version", "Print version info and exit"),
1146 opt::flag_s("v", "verbose", "Use verbose output"),
1147 ]
1148 }
1149
1150 /// Returns all rustc command line options, including metadata for
1151 /// each option, such as whether the option is part of the stable
1152 /// long-term interface for rustc.
rustc_optgroups() -> Vec<RustcOptGroup>1153 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1154 let mut opts = rustc_short_optgroups();
1155 opts.extend(vec![
1156 opt::multi_s(
1157 "",
1158 "extern",
1159 "Specify where an external rust library is located",
1160 "NAME[=PATH]",
1161 ),
1162 opt::multi_s(
1163 "",
1164 "extern-location",
1165 "Location where an external crate dependency is specified",
1166 "NAME=LOCATION",
1167 ),
1168 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1169 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1170 opt::opt_s(
1171 "",
1172 "error-format",
1173 "How errors and other messages are produced",
1174 "human|json|short",
1175 ),
1176 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1177 opt::opt_s(
1178 "",
1179 "color",
1180 "Configure coloring of output:
1181 auto = colorize, if output goes to a tty (default);
1182 always = always colorize output;
1183 never = never colorize output",
1184 "auto|always|never",
1185 ),
1186 opt::multi_s(
1187 "",
1188 "remap-path-prefix",
1189 "Remap source names in all output (compiler messages and output files)",
1190 "FROM=TO",
1191 ),
1192 ]);
1193 opts
1194 }
1195
get_cmd_lint_options( matches: &getopts::Matches, error_format: ErrorOutputType, ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>)1196 pub fn get_cmd_lint_options(
1197 matches: &getopts::Matches,
1198 error_format: ErrorOutputType,
1199 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1200 let mut lint_opts_with_position = vec![];
1201 let mut describe_lints = false;
1202
1203 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1204 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1205 if lint_name == "help" {
1206 describe_lints = true;
1207 } else {
1208 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1209 }
1210 }
1211 }
1212
1213 lint_opts_with_position.sort_by_key(|x| x.0);
1214 let lint_opts = lint_opts_with_position
1215 .iter()
1216 .cloned()
1217 .map(|(_, lint_name, level)| (lint_name, level))
1218 .collect();
1219
1220 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1221 lint::Level::from_str(&cap)
1222 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1223 });
1224
1225 (lint_opts, describe_lints, lint_cap)
1226 }
1227
1228 /// Parses the `--color` flag.
parse_color(matches: &getopts::Matches) -> ColorConfig1229 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1230 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1231 Some("auto") => ColorConfig::Auto,
1232 Some("always") => ColorConfig::Always,
1233 Some("never") => ColorConfig::Never,
1234
1235 None => ColorConfig::Auto,
1236
1237 Some(arg) => early_error(
1238 ErrorOutputType::default(),
1239 &format!(
1240 "argument for `--color` must be auto, \
1241 always or never (instead was `{}`)",
1242 arg
1243 ),
1244 ),
1245 }
1246 }
1247
1248 /// Possible json config files
1249 pub struct JsonConfig {
1250 pub json_rendered: HumanReadableErrorType,
1251 pub json_artifact_notifications: bool,
1252 pub json_unused_externs: bool,
1253 }
1254
1255 /// Parse the `--json` flag.
1256 ///
1257 /// The first value returned is how to render JSON diagnostics, and the second
1258 /// is whether or not artifact notifications are enabled.
parse_json(matches: &getopts::Matches) -> JsonConfig1259 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1260 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1261 HumanReadableErrorType::Default;
1262 let mut json_color = ColorConfig::Never;
1263 let mut json_artifact_notifications = false;
1264 let mut json_unused_externs = false;
1265 for option in matches.opt_strs("json") {
1266 // For now conservatively forbid `--color` with `--json` since `--json`
1267 // won't actually be emitting any colors and anything colorized is
1268 // embedded in a diagnostic message anyway.
1269 if matches.opt_str("color").is_some() {
1270 early_error(
1271 ErrorOutputType::default(),
1272 "cannot specify the `--color` option with `--json`",
1273 );
1274 }
1275
1276 for sub_option in option.split(',') {
1277 match sub_option {
1278 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1279 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1280 "artifacts" => json_artifact_notifications = true,
1281 "unused-externs" => json_unused_externs = true,
1282 s => early_error(
1283 ErrorOutputType::default(),
1284 &format!("unknown `--json` option `{}`", s),
1285 ),
1286 }
1287 }
1288 }
1289
1290 JsonConfig {
1291 json_rendered: json_rendered(json_color),
1292 json_artifact_notifications,
1293 json_unused_externs,
1294 }
1295 }
1296
1297 /// Parses the `--error-format` flag.
parse_error_format( matches: &getopts::Matches, color: ColorConfig, json_rendered: HumanReadableErrorType, ) -> ErrorOutputType1298 pub fn parse_error_format(
1299 matches: &getopts::Matches,
1300 color: ColorConfig,
1301 json_rendered: HumanReadableErrorType,
1302 ) -> ErrorOutputType {
1303 // We need the `opts_present` check because the driver will send us Matches
1304 // with only stable options if no unstable options are used. Since error-format
1305 // is unstable, it will not be present. We have to use `opts_present` not
1306 // `opt_present` because the latter will panic.
1307 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1308 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1309 None | Some("human") => {
1310 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1311 }
1312 Some("human-annotate-rs") => {
1313 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1314 }
1315 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1316 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1317 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1318
1319 Some(arg) => early_error(
1320 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1321 &format!(
1322 "argument for `--error-format` must be `human`, `json` or \
1323 `short` (instead was `{}`)",
1324 arg
1325 ),
1326 ),
1327 }
1328 } else {
1329 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1330 };
1331
1332 match error_format {
1333 ErrorOutputType::Json { .. } => {}
1334
1335 // Conservatively require that the `--json` argument is coupled with
1336 // `--error-format=json`. This means that `--json` is specified we
1337 // should actually be emitting JSON blobs.
1338 _ if !matches.opt_strs("json").is_empty() => {
1339 early_error(
1340 ErrorOutputType::default(),
1341 "using `--json` requires also using `--error-format=json`",
1342 );
1343 }
1344
1345 _ => {}
1346 }
1347
1348 error_format
1349 }
1350
parse_crate_edition(matches: &getopts::Matches) -> Edition1351 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1352 let edition = match matches.opt_str("edition") {
1353 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1354 early_error(
1355 ErrorOutputType::default(),
1356 &format!(
1357 "argument for `--edition` must be one of: \
1358 {}. (instead was `{}`)",
1359 EDITION_NAME_LIST, arg
1360 ),
1361 )
1362 }),
1363 None => DEFAULT_EDITION,
1364 };
1365
1366 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1367 let is_nightly = nightly_options::match_is_nightly_build(matches);
1368 let msg = if !is_nightly {
1369 format!(
1370 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1371 edition, LATEST_STABLE_EDITION
1372 )
1373 } else {
1374 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1375 };
1376 early_error(ErrorOutputType::default(), &msg)
1377 }
1378
1379 edition
1380 }
1381
check_debug_option_stability( debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, json_rendered: HumanReadableErrorType, )1382 fn check_debug_option_stability(
1383 debugging_opts: &DebuggingOptions,
1384 error_format: ErrorOutputType,
1385 json_rendered: HumanReadableErrorType,
1386 ) {
1387 if !debugging_opts.unstable_options {
1388 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1389 early_error(
1390 ErrorOutputType::Json { pretty: false, json_rendered },
1391 "`--error-format=pretty-json` is unstable",
1392 );
1393 }
1394 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1395 error_format
1396 {
1397 early_error(
1398 ErrorOutputType::Json { pretty: false, json_rendered },
1399 "`--error-format=human-annotate-rs` is unstable",
1400 );
1401 }
1402 }
1403 }
1404
parse_output_types( debugging_opts: &DebuggingOptions, matches: &getopts::Matches, error_format: ErrorOutputType, ) -> OutputTypes1405 fn parse_output_types(
1406 debugging_opts: &DebuggingOptions,
1407 matches: &getopts::Matches,
1408 error_format: ErrorOutputType,
1409 ) -> OutputTypes {
1410 let mut output_types = BTreeMap::new();
1411 if !debugging_opts.parse_only {
1412 for list in matches.opt_strs("emit") {
1413 for output_type in list.split(',') {
1414 let (shorthand, path) = match output_type.split_once('=') {
1415 None => (output_type, None),
1416 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1417 };
1418 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1419 early_error(
1420 error_format,
1421 &format!(
1422 "unknown emission type: `{}` - expected one of: {}",
1423 shorthand,
1424 OutputType::shorthands_display(),
1425 ),
1426 )
1427 });
1428 output_types.insert(output_type, path);
1429 }
1430 }
1431 };
1432 if output_types.is_empty() {
1433 output_types.insert(OutputType::Exe, None);
1434 }
1435 OutputTypes(output_types)
1436 }
1437
should_override_cgus_and_disable_thinlto( output_types: &OutputTypes, matches: &getopts::Matches, error_format: ErrorOutputType, mut codegen_units: Option<usize>, ) -> (bool, Option<usize>)1438 fn should_override_cgus_and_disable_thinlto(
1439 output_types: &OutputTypes,
1440 matches: &getopts::Matches,
1441 error_format: ErrorOutputType,
1442 mut codegen_units: Option<usize>,
1443 ) -> (bool, Option<usize>) {
1444 let mut disable_thinlto = false;
1445 // Issue #30063: if user requests LLVM-related output to one
1446 // particular path, disable codegen-units.
1447 let incompatible: Vec<_> = output_types
1448 .0
1449 .iter()
1450 .map(|ot_path| ot_path.0)
1451 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1452 .map(|ot| ot.shorthand())
1453 .collect();
1454 if !incompatible.is_empty() {
1455 match codegen_units {
1456 Some(n) if n > 1 => {
1457 if matches.opt_present("o") {
1458 for ot in &incompatible {
1459 early_warn(
1460 error_format,
1461 &format!(
1462 "`--emit={}` with `-o` incompatible with \
1463 `-C codegen-units=N` for N > 1",
1464 ot
1465 ),
1466 );
1467 }
1468 early_warn(error_format, "resetting to default -C codegen-units=1");
1469 codegen_units = Some(1);
1470 disable_thinlto = true;
1471 }
1472 }
1473 _ => {
1474 codegen_units = Some(1);
1475 disable_thinlto = true;
1476 }
1477 }
1478 }
1479
1480 if codegen_units == Some(0) {
1481 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1482 }
1483
1484 (disable_thinlto, codegen_units)
1485 }
1486
check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType)1487 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1488 if debugging_opts.threads == 0 {
1489 early_error(error_format, "value for threads must be a positive non-zero integer");
1490 }
1491
1492 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1493 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1494 }
1495 }
1496
collect_print_requests( cg: &mut CodegenOptions, dopts: &mut DebuggingOptions, matches: &getopts::Matches, error_format: ErrorOutputType, ) -> Vec<PrintRequest>1497 fn collect_print_requests(
1498 cg: &mut CodegenOptions,
1499 dopts: &mut DebuggingOptions,
1500 matches: &getopts::Matches,
1501 error_format: ErrorOutputType,
1502 ) -> Vec<PrintRequest> {
1503 let mut prints = Vec::<PrintRequest>::new();
1504 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1505 prints.push(PrintRequest::TargetCPUs);
1506 cg.target_cpu = None;
1507 };
1508 if cg.target_feature == "help" {
1509 prints.push(PrintRequest::TargetFeatures);
1510 cg.target_feature = String::new();
1511 }
1512
1513 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1514 "crate-name" => PrintRequest::CrateName,
1515 "file-names" => PrintRequest::FileNames,
1516 "sysroot" => PrintRequest::Sysroot,
1517 "target-libdir" => PrintRequest::TargetLibdir,
1518 "cfg" => PrintRequest::Cfg,
1519 "target-list" => PrintRequest::TargetList,
1520 "target-cpus" => PrintRequest::TargetCPUs,
1521 "target-features" => PrintRequest::TargetFeatures,
1522 "relocation-models" => PrintRequest::RelocationModels,
1523 "code-models" => PrintRequest::CodeModels,
1524 "tls-models" => PrintRequest::TlsModels,
1525 "native-static-libs" => PrintRequest::NativeStaticLibs,
1526 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1527 "target-spec-json" => {
1528 if dopts.unstable_options {
1529 PrintRequest::TargetSpec
1530 } else {
1531 early_error(
1532 error_format,
1533 "the `-Z unstable-options` flag must also be passed to \
1534 enable the target-spec-json print option",
1535 );
1536 }
1537 }
1538 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1539 }));
1540
1541 prints
1542 }
1543
parse_target_triple( matches: &getopts::Matches, error_format: ErrorOutputType, ) -> TargetTriple1544 pub fn parse_target_triple(
1545 matches: &getopts::Matches,
1546 error_format: ErrorOutputType,
1547 ) -> TargetTriple {
1548 match matches.opt_str("target") {
1549 Some(target) if target.ends_with(".json") => {
1550 let path = Path::new(&target);
1551 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1552 early_error(error_format, &format!("target file {:?} does not exist", path))
1553 })
1554 }
1555 Some(target) => TargetTriple::TargetTriple(target),
1556 _ => TargetTriple::from_triple(host_triple()),
1557 }
1558 }
1559
parse_opt_level( matches: &getopts::Matches, cg: &CodegenOptions, error_format: ErrorOutputType, ) -> OptLevel1560 fn parse_opt_level(
1561 matches: &getopts::Matches,
1562 cg: &CodegenOptions,
1563 error_format: ErrorOutputType,
1564 ) -> OptLevel {
1565 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1566 // to use them interchangeably. However, because they're technically different flags,
1567 // we need to work out manually which should take precedence if both are supplied (i.e.
1568 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1569 // comparing them. Note that if a flag is not found, its position will be `None`, which
1570 // always compared less than `Some(_)`.
1571 let max_o = matches.opt_positions("O").into_iter().max();
1572 let max_c = matches
1573 .opt_strs_pos("C")
1574 .into_iter()
1575 .flat_map(|(i, s)| {
1576 // NB: This can match a string without `=`.
1577 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1578 })
1579 .max();
1580 if max_o > max_c {
1581 OptLevel::Default
1582 } else {
1583 match cg.opt_level.as_ref() {
1584 "0" => OptLevel::No,
1585 "1" => OptLevel::Less,
1586 "2" => OptLevel::Default,
1587 "3" => OptLevel::Aggressive,
1588 "s" => OptLevel::Size,
1589 "z" => OptLevel::SizeMin,
1590 arg => {
1591 early_error(
1592 error_format,
1593 &format!(
1594 "optimization level needs to be \
1595 between 0-3, s or z (instead was `{}`)",
1596 arg
1597 ),
1598 );
1599 }
1600 }
1601 }
1602 }
1603
select_debuginfo( matches: &getopts::Matches, cg: &CodegenOptions, error_format: ErrorOutputType, ) -> DebugInfo1604 fn select_debuginfo(
1605 matches: &getopts::Matches,
1606 cg: &CodegenOptions,
1607 error_format: ErrorOutputType,
1608 ) -> DebugInfo {
1609 let max_g = matches.opt_positions("g").into_iter().max();
1610 let max_c = matches
1611 .opt_strs_pos("C")
1612 .into_iter()
1613 .flat_map(|(i, s)| {
1614 // NB: This can match a string without `=`.
1615 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1616 })
1617 .max();
1618 if max_g > max_c {
1619 DebugInfo::Full
1620 } else {
1621 match cg.debuginfo {
1622 0 => DebugInfo::None,
1623 1 => DebugInfo::Limited,
1624 2 => DebugInfo::Full,
1625 arg => {
1626 early_error(
1627 error_format,
1628 &format!(
1629 "debug info level needs to be between \
1630 0-2 (instead was `{}`)",
1631 arg
1632 ),
1633 );
1634 }
1635 }
1636 }
1637 }
1638
parse_assert_incr_state( opt_assertion: &Option<String>, error_format: ErrorOutputType, ) -> Option<IncrementalStateAssertion>1639 crate fn parse_assert_incr_state(
1640 opt_assertion: &Option<String>,
1641 error_format: ErrorOutputType,
1642 ) -> Option<IncrementalStateAssertion> {
1643 match opt_assertion {
1644 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1645 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1646 Some(s) => early_error(
1647 error_format,
1648 &format!("unexpected incremental state assertion value: {}", s),
1649 ),
1650 None => None,
1651 }
1652 }
1653
parse_native_lib_kind( matches: &getopts::Matches, kind: &str, error_format: ErrorOutputType, ) -> (NativeLibKind, Option<bool>)1654 fn parse_native_lib_kind(
1655 matches: &getopts::Matches,
1656 kind: &str,
1657 error_format: ErrorOutputType,
1658 ) -> (NativeLibKind, Option<bool>) {
1659 let is_nightly = nightly_options::match_is_nightly_build(matches);
1660 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1661
1662 let (kind, modifiers) = match kind.split_once(':') {
1663 None => (kind, None),
1664 Some((kind, modifiers)) => (kind, Some(modifiers)),
1665 };
1666
1667 let kind = match kind {
1668 "dylib" => NativeLibKind::Dylib { as_needed: None },
1669 "framework" => NativeLibKind::Framework { as_needed: None },
1670 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1671 "static-nobundle" => {
1672 early_warn(
1673 error_format,
1674 "library kind `static-nobundle` has been superseded by specifying \
1675 `-bundle` on library kind `static`. Try `static:-bundle`",
1676 );
1677 if modifiers.is_some() {
1678 early_error(
1679 error_format,
1680 "linking modifier can't be used with library kind `static-nobundle`",
1681 )
1682 }
1683 if !is_nightly {
1684 early_error(
1685 error_format,
1686 "library kind `static-nobundle` are currently unstable and only accepted on \
1687 the nightly compiler",
1688 );
1689 }
1690 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1691 }
1692 s => early_error(
1693 error_format,
1694 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1695 ),
1696 };
1697 match modifiers {
1698 None => (kind, None),
1699 Some(modifiers) => {
1700 if !is_nightly {
1701 early_error(
1702 error_format,
1703 "linking modifiers are currently unstable and only accepted on \
1704 the nightly compiler",
1705 );
1706 }
1707 if !enable_unstable {
1708 early_error(
1709 error_format,
1710 "linking modifiers are currently unstable, \
1711 the `-Z unstable-options` flag must also be passed to use it",
1712 )
1713 }
1714 parse_native_lib_modifiers(kind, modifiers, error_format)
1715 }
1716 }
1717 }
1718
parse_native_lib_modifiers( mut kind: NativeLibKind, modifiers: &str, error_format: ErrorOutputType, ) -> (NativeLibKind, Option<bool>)1719 fn parse_native_lib_modifiers(
1720 mut kind: NativeLibKind,
1721 modifiers: &str,
1722 error_format: ErrorOutputType,
1723 ) -> (NativeLibKind, Option<bool>) {
1724 let mut verbatim = None;
1725 for modifier in modifiers.split(',') {
1726 let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1727 Some(m) => (m, modifier.starts_with('+')),
1728 None => early_error(
1729 error_format,
1730 "invalid linking modifier syntax, expected '+' or '-' prefix \
1731 before one of: bundle, verbatim, whole-archive, as-needed",
1732 ),
1733 };
1734
1735 match (modifier, &mut kind) {
1736 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1737 *bundle = Some(value);
1738 }
1739 ("bundle", _) => early_error(
1740 error_format,
1741 "bundle linking modifier is only compatible with \
1742 `static` linking kind",
1743 ),
1744
1745 ("verbatim", _) => verbatim = Some(value),
1746
1747 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1748 *whole_archive = Some(value);
1749 }
1750 ("whole-archive", _) => early_error(
1751 error_format,
1752 "whole-archive linking modifier is only compatible with \
1753 `static` linking kind",
1754 ),
1755
1756 ("as-needed", NativeLibKind::Dylib { as_needed })
1757 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1758 *as_needed = Some(value);
1759 }
1760 ("as-needed", _) => early_error(
1761 error_format,
1762 "as-needed linking modifier is only compatible with \
1763 `dylib` and `framework` linking kinds",
1764 ),
1765
1766 _ => early_error(
1767 error_format,
1768 &format!(
1769 "unrecognized linking modifier `{}`, expected one \
1770 of: bundle, verbatim, whole-archive, as-needed",
1771 modifier
1772 ),
1773 ),
1774 }
1775 }
1776
1777 (kind, verbatim)
1778 }
1779
parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib>1780 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1781 matches
1782 .opt_strs("l")
1783 .into_iter()
1784 .map(|s| {
1785 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1786 // where KIND is one of "dylib", "framework", "static" and
1787 // where MODIFIERS are a comma separated list of supported modifiers
1788 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1789 // with either + or - to indicate whether it is enabled or disabled.
1790 // The last value specified for a given modifier wins.
1791 let (name, kind, verbatim) = match s.split_once('=') {
1792 None => (s, NativeLibKind::Unspecified, None),
1793 Some((kind, name)) => {
1794 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1795 (name.to_string(), kind, verbatim)
1796 }
1797 };
1798
1799 let (name, new_name) = match name.split_once(':') {
1800 None => (name, None),
1801 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1802 };
1803 NativeLib { name, new_name, kind, verbatim }
1804 })
1805 .collect()
1806 }
1807
parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode1808 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1809 match dopts.borrowck.as_ref() {
1810 "migrate" => BorrowckMode::Migrate,
1811 "mir" => BorrowckMode::Mir,
1812 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1813 }
1814 }
1815
parse_externs( matches: &getopts::Matches, debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> Externs1816 pub fn parse_externs(
1817 matches: &getopts::Matches,
1818 debugging_opts: &DebuggingOptions,
1819 error_format: ErrorOutputType,
1820 ) -> Externs {
1821 let is_unstable_enabled = debugging_opts.unstable_options;
1822 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1823 for arg in matches.opt_strs("extern") {
1824 let (name, path) = match arg.split_once('=') {
1825 None => (arg, None),
1826 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1827 };
1828 let (options, name) = match name.split_once(':') {
1829 None => (None, name),
1830 Some((opts, name)) => (Some(opts), name.to_string()),
1831 };
1832
1833 let path = path.map(|p| CanonicalizedPath::new(p));
1834
1835 let entry = externs.entry(name.to_owned());
1836
1837 use std::collections::btree_map::Entry;
1838
1839 let entry = if let Some(path) = path {
1840 // --extern prelude_name=some_file.rlib
1841 match entry {
1842 Entry::Vacant(vacant) => {
1843 let files = BTreeSet::from_iter(iter::once(path));
1844 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1845 }
1846 Entry::Occupied(occupied) => {
1847 let ext_ent = occupied.into_mut();
1848 match ext_ent {
1849 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1850 files.insert(path);
1851 }
1852 ExternEntry {
1853 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1854 ..
1855 } => {
1856 // Exact paths take precedence over search directories.
1857 let files = BTreeSet::from_iter(iter::once(path));
1858 *location = ExternLocation::ExactPaths(files);
1859 }
1860 }
1861 ext_ent
1862 }
1863 }
1864 } else {
1865 // --extern prelude_name
1866 match entry {
1867 Entry::Vacant(vacant) => {
1868 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1869 }
1870 Entry::Occupied(occupied) => {
1871 // Ignore if already specified.
1872 occupied.into_mut()
1873 }
1874 }
1875 };
1876
1877 let mut is_private_dep = false;
1878 let mut add_prelude = true;
1879 if let Some(opts) = options {
1880 if !is_unstable_enabled {
1881 early_error(
1882 error_format,
1883 "the `-Z unstable-options` flag must also be passed to \
1884 enable `--extern options",
1885 );
1886 }
1887 for opt in opts.split(',') {
1888 match opt {
1889 "priv" => is_private_dep = true,
1890 "noprelude" => {
1891 if let ExternLocation::ExactPaths(_) = &entry.location {
1892 add_prelude = false;
1893 } else {
1894 early_error(
1895 error_format,
1896 "the `noprelude` --extern option requires a file path",
1897 );
1898 }
1899 }
1900 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1901 }
1902 }
1903 }
1904
1905 // Crates start out being not private, and go to being private `priv`
1906 // is specified.
1907 entry.is_private_dep |= is_private_dep;
1908 // If any flag is missing `noprelude`, then add to the prelude.
1909 entry.add_prelude |= add_prelude;
1910 }
1911 Externs(externs)
1912 }
1913
parse_extern_dep_specs( matches: &getopts::Matches, debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> ExternDepSpecs1914 fn parse_extern_dep_specs(
1915 matches: &getopts::Matches,
1916 debugging_opts: &DebuggingOptions,
1917 error_format: ErrorOutputType,
1918 ) -> ExternDepSpecs {
1919 let is_unstable_enabled = debugging_opts.unstable_options;
1920 let mut map = BTreeMap::new();
1921
1922 for arg in matches.opt_strs("extern-location") {
1923 if !is_unstable_enabled {
1924 early_error(
1925 error_format,
1926 "`--extern-location` option is unstable: set `-Z unstable-options`",
1927 );
1928 }
1929
1930 let mut parts = arg.splitn(2, '=');
1931 let name = parts.next().unwrap_or_else(|| {
1932 early_error(error_format, "`--extern-location` value must not be empty")
1933 });
1934 let loc = parts.next().unwrap_or_else(|| {
1935 early_error(
1936 error_format,
1937 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1938 )
1939 });
1940
1941 let locparts: Vec<_> = loc.split(':').collect();
1942 let spec = match &locparts[..] {
1943 ["raw", ..] => {
1944 // Don't want `:` split string
1945 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1946 early_error(error_format, "`--extern-location`: missing `raw` location")
1947 });
1948 ExternDepSpec::Raw(raw.to_string())
1949 }
1950 ["json", ..] => {
1951 // Don't want `:` split string
1952 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1953 early_error(error_format, "`--extern-location`: missing `json` location")
1954 });
1955 let json = json::from_str(raw).unwrap_or_else(|_| {
1956 early_error(
1957 error_format,
1958 &format!("`--extern-location`: malformed json location `{}`", raw),
1959 )
1960 });
1961 ExternDepSpec::Json(json)
1962 }
1963 [bad, ..] => early_error(
1964 error_format,
1965 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1966 ),
1967 [] => early_error(error_format, "missing location specification"),
1968 };
1969
1970 map.insert(name.to_string(), spec);
1971 }
1972
1973 ExternDepSpecs::new(map)
1974 }
1975
parse_remap_path_prefix( matches: &getopts::Matches, debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> Vec<(PathBuf, PathBuf)>1976 fn parse_remap_path_prefix(
1977 matches: &getopts::Matches,
1978 debugging_opts: &DebuggingOptions,
1979 error_format: ErrorOutputType,
1980 ) -> Vec<(PathBuf, PathBuf)> {
1981 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
1982 .opt_strs("remap-path-prefix")
1983 .into_iter()
1984 .map(|remap| match remap.rsplit_once('=') {
1985 None => early_error(
1986 error_format,
1987 "--remap-path-prefix must contain '=' between FROM and TO",
1988 ),
1989 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1990 })
1991 .collect();
1992 match &debugging_opts.remap_cwd_prefix {
1993 Some(to) => match std::env::current_dir() {
1994 Ok(cwd) => mapping.push((cwd, to.clone())),
1995 Err(_) => (),
1996 },
1997 None => (),
1998 };
1999 mapping
2000 }
2001
build_session_options(matches: &getopts::Matches) -> Options2002 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2003 let color = parse_color(matches);
2004
2005 let edition = parse_crate_edition(matches);
2006
2007 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
2008 parse_json(matches);
2009
2010 let error_format = parse_error_format(matches, color, json_rendered);
2011
2012 let unparsed_crate_types = matches.opt_strs("crate-type");
2013 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2014 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2015
2016 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2017 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2018
2019 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2020
2021 if !debugging_opts.unstable_options && json_unused_externs {
2022 early_error(
2023 error_format,
2024 "the `-Z unstable-options` flag must also be passed to enable \
2025 the flag `--json=unused-externs`",
2026 );
2027 }
2028
2029 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2030
2031 let mut cg = CodegenOptions::build(matches, error_format);
2032 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2033 &output_types,
2034 matches,
2035 error_format,
2036 cg.codegen_units,
2037 );
2038
2039 check_thread_count(&debugging_opts, error_format);
2040
2041 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2042
2043 let assert_incr_state =
2044 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2045
2046 if debugging_opts.profile && incremental.is_some() {
2047 early_error(
2048 error_format,
2049 "can't instrument with gcov profiling when compiling incrementally",
2050 );
2051 }
2052 if debugging_opts.profile {
2053 match codegen_units {
2054 Some(1) => {}
2055 None => codegen_units = Some(1),
2056 Some(_) => early_error(
2057 error_format,
2058 "can't instrument with gcov profiling with multiple codegen units",
2059 ),
2060 }
2061 }
2062
2063 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2064 early_error(
2065 error_format,
2066 "options `-C profile-generate` and `-C profile-use` are exclusive",
2067 );
2068 }
2069
2070 if debugging_opts.profile_sample_use.is_some()
2071 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2072 {
2073 early_error(
2074 error_format,
2075 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2076 );
2077 }
2078
2079 if debugging_opts.instrument_coverage.is_some()
2080 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2081 {
2082 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2083 early_error(
2084 error_format,
2085 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2086 or `-C profile-generate`",
2087 );
2088 }
2089
2090 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2091 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2092 // multiple runs, including some changes to source code; so mangled names must be consistent
2093 // across compilations.
2094 match debugging_opts.symbol_mangling_version {
2095 None => {
2096 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2097 }
2098 Some(SymbolManglingVersion::Legacy) => {
2099 early_warn(
2100 error_format,
2101 "-Z instrument-coverage requires symbol mangling version `v0`, \
2102 but `-Z symbol-mangling-version=legacy` was specified",
2103 );
2104 }
2105 Some(SymbolManglingVersion::V0) => {}
2106 }
2107 }
2108
2109 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2110 debugging_opts.graphviz_font = graphviz_font;
2111 }
2112
2113 if !cg.embed_bitcode {
2114 match cg.lto {
2115 LtoCli::No | LtoCli::Unspecified => {}
2116 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2117 error_format,
2118 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2119 ),
2120 }
2121 }
2122
2123 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2124
2125 let cg = cg;
2126
2127 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2128 let target_triple = parse_target_triple(matches, error_format);
2129 let opt_level = parse_opt_level(matches, &cg, error_format);
2130 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2131 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2132 // for more details.
2133 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2134 let debuginfo = select_debuginfo(matches, &cg, error_format);
2135
2136 let mut search_paths = vec![];
2137 for s in &matches.opt_strs("L") {
2138 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2139 }
2140
2141 let libs = parse_libs(matches, error_format);
2142
2143 let test = matches.opt_present("test");
2144
2145 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2146
2147 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2148 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2149 }
2150
2151 let externs = parse_externs(matches, &debugging_opts, error_format);
2152 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2153
2154 let crate_name = matches.opt_str("crate-name");
2155
2156 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2157
2158 let pretty = parse_pretty(&debugging_opts, error_format);
2159
2160 if !debugging_opts.unstable_options
2161 && !target_triple.triple().contains("apple")
2162 && cg.split_debuginfo.is_some()
2163 {
2164 {
2165 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2166 }
2167 }
2168
2169 // Try to find a directory containing the Rust `src`, for more details see
2170 // the doc comment on the `real_rust_source_base_dir` field.
2171 let tmp_buf;
2172 let sysroot = match &sysroot_opt {
2173 Some(s) => s,
2174 None => {
2175 tmp_buf = crate::filesearch::get_or_default_sysroot();
2176 &tmp_buf
2177 }
2178 };
2179 let real_rust_source_base_dir = {
2180 // This is the location used by the `rust-src` `rustup` component.
2181 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2182 if let Ok(metadata) = candidate.symlink_metadata() {
2183 // Replace the symlink rustbuild creates, with its destination.
2184 // We could try to use `fs::canonicalize` instead, but that might
2185 // produce unnecessarily verbose path.
2186 if metadata.file_type().is_symlink() {
2187 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2188 candidate = symlink_dest;
2189 }
2190 }
2191 }
2192
2193 // Only use this directory if it has a file we can expect to always find.
2194 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2195 };
2196
2197 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2198 early_error(error_format, &format!("Current directory is invalid: {}", e));
2199 });
2200
2201 let (path, remapped) =
2202 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2203 let working_dir = if remapped {
2204 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2205 } else {
2206 RealFileName::LocalPath(path)
2207 };
2208
2209 Options {
2210 assert_incr_state,
2211 crate_types,
2212 optimize: opt_level,
2213 debuginfo,
2214 lint_opts,
2215 lint_cap,
2216 describe_lints,
2217 output_types,
2218 search_paths,
2219 maybe_sysroot: sysroot_opt,
2220 target_triple,
2221 test,
2222 incremental,
2223 debugging_opts,
2224 prints,
2225 borrowck_mode,
2226 cg,
2227 error_format,
2228 externs,
2229 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2230 extern_dep_specs,
2231 crate_name,
2232 alt_std_name: None,
2233 libs,
2234 debug_assertions,
2235 actually_rustdoc: false,
2236 trimmed_def_paths: TrimmedDefPaths::default(),
2237 cli_forced_codegen_units: codegen_units,
2238 cli_forced_thinlto_off: disable_thinlto,
2239 remap_path_prefix,
2240 real_rust_source_base_dir,
2241 edition,
2242 json_artifact_notifications,
2243 json_unused_externs,
2244 pretty,
2245 working_dir,
2246 }
2247 }
2248
parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode>2249 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2250 use PpMode::*;
2251
2252 let first = match debugging_opts.unpretty.as_deref()? {
2253 "normal" => Source(PpSourceMode::Normal),
2254 "identified" => Source(PpSourceMode::Identified),
2255 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2256 "expanded" => Source(PpSourceMode::Expanded),
2257 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2258 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2259 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2260 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2261 "hir" => Hir(PpHirMode::Normal),
2262 "hir,identified" => Hir(PpHirMode::Identified),
2263 "hir,typed" => Hir(PpHirMode::Typed),
2264 "hir-tree" => HirTree,
2265 "thir-tree" => ThirTree,
2266 "mir" => Mir,
2267 "mir-cfg" => MirCFG,
2268 name => early_error(
2269 efmt,
2270 &format!(
2271 "argument to `unpretty` must be one of `normal`, \
2272 `expanded`, `identified`, `expanded,identified`, \
2273 `expanded,hygiene`, `everybody_loops`, \
2274 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2275 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2276 name
2277 ),
2278 ),
2279 };
2280 tracing::debug!("got unpretty option: {:?}", first);
2281 Some(first)
2282 }
2283
make_crate_type_option() -> RustcOptGroup2284 pub fn make_crate_type_option() -> RustcOptGroup {
2285 opt::multi_s(
2286 "",
2287 "crate-type",
2288 "Comma separated list of types of crates
2289 for the compiler to emit",
2290 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2291 )
2292 }
2293
parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String>2294 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2295 let mut crate_types: Vec<CrateType> = Vec::new();
2296 for unparsed_crate_type in &list_list {
2297 for part in unparsed_crate_type.split(',') {
2298 let new_part = match part {
2299 "lib" => default_lib_output(),
2300 "rlib" => CrateType::Rlib,
2301 "staticlib" => CrateType::Staticlib,
2302 "dylib" => CrateType::Dylib,
2303 "cdylib" => CrateType::Cdylib,
2304 "bin" => CrateType::Executable,
2305 "proc-macro" => CrateType::ProcMacro,
2306 _ => return Err(format!("unknown crate type: `{}`", part)),
2307 };
2308 if !crate_types.contains(&new_part) {
2309 crate_types.push(new_part)
2310 }
2311 }
2312 }
2313
2314 Ok(crate_types)
2315 }
2316
2317 pub mod nightly_options {
2318 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2319 use crate::early_error;
2320 use rustc_feature::UnstableFeatures;
2321
is_unstable_enabled(matches: &getopts::Matches) -> bool2322 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2323 match_is_nightly_build(matches)
2324 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2325 }
2326
match_is_nightly_build(matches: &getopts::Matches) -> bool2327 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2328 is_nightly_build(matches.opt_str("crate-name").as_deref())
2329 }
2330
is_nightly_build(krate: Option<&str>) -> bool2331 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2332 UnstableFeatures::from_environment(krate).is_nightly_build()
2333 }
2334
check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup])2335 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2336 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2337 let really_allows_unstable_options = match_is_nightly_build(matches);
2338
2339 for opt in flags.iter() {
2340 if opt.stability == OptionStability::Stable {
2341 continue;
2342 }
2343 if !matches.opt_present(opt.name) {
2344 continue;
2345 }
2346 if opt.name != "Z" && !has_z_unstable_option {
2347 early_error(
2348 ErrorOutputType::default(),
2349 &format!(
2350 "the `-Z unstable-options` flag must also be passed to enable \
2351 the flag `{}`",
2352 opt.name
2353 ),
2354 );
2355 }
2356 if really_allows_unstable_options {
2357 continue;
2358 }
2359 match opt.stability {
2360 OptionStability::Unstable => {
2361 let msg = format!(
2362 "the option `{}` is only accepted on the \
2363 nightly compiler",
2364 opt.name
2365 );
2366 early_error(ErrorOutputType::default(), &msg);
2367 }
2368 OptionStability::Stable => {}
2369 }
2370 }
2371 }
2372 }
2373
2374 impl fmt::Display for CrateType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2376 match *self {
2377 CrateType::Executable => "bin".fmt(f),
2378 CrateType::Dylib => "dylib".fmt(f),
2379 CrateType::Rlib => "rlib".fmt(f),
2380 CrateType::Staticlib => "staticlib".fmt(f),
2381 CrateType::Cdylib => "cdylib".fmt(f),
2382 CrateType::ProcMacro => "proc-macro".fmt(f),
2383 }
2384 }
2385 }
2386
2387 #[derive(Copy, Clone, PartialEq, Debug)]
2388 pub enum PpSourceMode {
2389 /// `-Zunpretty=normal`
2390 Normal,
2391 /// `-Zunpretty=everybody_loops`
2392 EveryBodyLoops,
2393 /// `-Zunpretty=expanded`
2394 Expanded,
2395 /// `-Zunpretty=identified`
2396 Identified,
2397 /// `-Zunpretty=expanded,identified`
2398 ExpandedIdentified,
2399 /// `-Zunpretty=expanded,hygiene`
2400 ExpandedHygiene,
2401 }
2402
2403 #[derive(Copy, Clone, PartialEq, Debug)]
2404 pub enum PpAstTreeMode {
2405 /// `-Zunpretty=ast`
2406 Normal,
2407 /// `-Zunpretty=ast,expanded`
2408 Expanded,
2409 }
2410
2411 #[derive(Copy, Clone, PartialEq, Debug)]
2412 pub enum PpHirMode {
2413 /// `-Zunpretty=hir`
2414 Normal,
2415 /// `-Zunpretty=hir,identified`
2416 Identified,
2417 /// `-Zunpretty=hir,typed`
2418 Typed,
2419 }
2420
2421 #[derive(Copy, Clone, PartialEq, Debug)]
2422 pub enum PpMode {
2423 /// Options that print the source code, i.e.
2424 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2425 Source(PpSourceMode),
2426 AstTree(PpAstTreeMode),
2427 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2428 Hir(PpHirMode),
2429 /// `-Zunpretty=hir-tree`
2430 HirTree,
2431 /// `-Zunpretty=thir-tree`
2432 ThirTree,
2433 /// `-Zunpretty=mir`
2434 Mir,
2435 /// `-Zunpretty=mir-cfg`
2436 MirCFG,
2437 }
2438
2439 impl PpMode {
needs_ast_map(&self) -> bool2440 pub fn needs_ast_map(&self) -> bool {
2441 use PpMode::*;
2442 use PpSourceMode::*;
2443 match *self {
2444 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2445
2446 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2447 | AstTree(PpAstTreeMode::Expanded)
2448 | Hir(_)
2449 | HirTree
2450 | ThirTree
2451 | Mir
2452 | MirCFG => true,
2453 }
2454 }
2455
needs_analysis(&self) -> bool2456 pub fn needs_analysis(&self) -> bool {
2457 use PpMode::*;
2458 matches!(*self, Mir | MirCFG | ThirTree)
2459 }
2460 }
2461
2462 /// Command-line arguments passed to the compiler have to be incorporated with
2463 /// the dependency tracking system for incremental compilation. This module
2464 /// provides some utilities to make this more convenient.
2465 ///
2466 /// The values of all command-line arguments that are relevant for dependency
2467 /// tracking are hashed into a single value that determines whether the
2468 /// incremental compilation cache can be re-used or not. This hashing is done
2469 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2470 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2471 /// the hash of which is order dependent, but we might not want the order of
2472 /// arguments to make a difference for the hash).
2473 ///
2474 /// However, since the value provided by `Hash::hash` often *is* suitable,
2475 /// especially for primitive types, there is the
2476 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2477 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2478 /// we have an opt-in scheme here, so one is hopefully forced to think about
2479 /// how the hash should be calculated when adding a new command-line argument.
2480 crate mod dep_tracking {
2481 use super::LdImpl;
2482 use super::{
2483 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2484 LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2485 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2486 };
2487 use crate::lint;
2488 use crate::options::WasiExecModel;
2489 use crate::utils::{NativeLib, NativeLibKind};
2490 use rustc_feature::UnstableFeatures;
2491 use rustc_span::edition::Edition;
2492 use rustc_span::RealFileName;
2493 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2494 use rustc_target::spec::{
2495 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2496 };
2497 use std::collections::hash_map::DefaultHasher;
2498 use std::collections::BTreeMap;
2499 use std::hash::Hash;
2500 use std::num::NonZeroUsize;
2501 use std::path::PathBuf;
2502
2503 pub trait DepTrackingHash {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2504 fn hash(
2505 &self,
2506 hasher: &mut DefaultHasher,
2507 error_format: ErrorOutputType,
2508 for_crate_hash: bool,
2509 );
2510 }
2511
2512 macro_rules! impl_dep_tracking_hash_via_hash {
2513 ($($t:ty),+ $(,)?) => {$(
2514 impl DepTrackingHash for $t {
2515 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2516 Hash::hash(self, hasher);
2517 }
2518 }
2519 )+};
2520 }
2521
2522 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2523 fn hash(
2524 &self,
2525 hasher: &mut DefaultHasher,
2526 error_format: ErrorOutputType,
2527 for_crate_hash: bool,
2528 ) {
2529 match self {
2530 Some(x) => {
2531 Hash::hash(&1, hasher);
2532 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2533 }
2534 None => Hash::hash(&0, hasher),
2535 }
2536 }
2537 }
2538
2539 impl_dep_tracking_hash_via_hash!(
2540 bool,
2541 usize,
2542 NonZeroUsize,
2543 u64,
2544 String,
2545 PathBuf,
2546 lint::Level,
2547 WasiExecModel,
2548 u32,
2549 RelocModel,
2550 CodeModel,
2551 TlsModel,
2552 InstrumentCoverage,
2553 CrateType,
2554 MergeFunctions,
2555 PanicStrategy,
2556 RelroLevel,
2557 Passes,
2558 OptLevel,
2559 LtoCli,
2560 DebugInfo,
2561 UnstableFeatures,
2562 NativeLib,
2563 NativeLibKind,
2564 SanitizerSet,
2565 CFGuard,
2566 TargetTriple,
2567 Edition,
2568 LinkerPluginLto,
2569 SplitDebuginfo,
2570 StackProtector,
2571 SwitchWithOptPath,
2572 SymbolManglingVersion,
2573 SourceFileHashAlgorithm,
2574 TrimmedDefPaths,
2575 Option<LdImpl>,
2576 OutputType,
2577 RealFileName,
2578 LocationDetail,
2579 );
2580
2581 impl<T1, T2> DepTrackingHash for (T1, T2)
2582 where
2583 T1: DepTrackingHash,
2584 T2: DepTrackingHash,
2585 {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2586 fn hash(
2587 &self,
2588 hasher: &mut DefaultHasher,
2589 error_format: ErrorOutputType,
2590 for_crate_hash: bool,
2591 ) {
2592 Hash::hash(&0, hasher);
2593 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2594 Hash::hash(&1, hasher);
2595 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2596 }
2597 }
2598
2599 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2600 where
2601 T1: DepTrackingHash,
2602 T2: DepTrackingHash,
2603 T3: DepTrackingHash,
2604 {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2605 fn hash(
2606 &self,
2607 hasher: &mut DefaultHasher,
2608 error_format: ErrorOutputType,
2609 for_crate_hash: bool,
2610 ) {
2611 Hash::hash(&0, hasher);
2612 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2613 Hash::hash(&1, hasher);
2614 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2615 Hash::hash(&2, hasher);
2616 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2617 }
2618 }
2619
2620 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2621 fn hash(
2622 &self,
2623 hasher: &mut DefaultHasher,
2624 error_format: ErrorOutputType,
2625 for_crate_hash: bool,
2626 ) {
2627 Hash::hash(&self.len(), hasher);
2628 for (index, elem) in self.iter().enumerate() {
2629 Hash::hash(&index, hasher);
2630 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2631 }
2632 }
2633 }
2634
2635 impl DepTrackingHash for OutputTypes {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2636 fn hash(
2637 &self,
2638 hasher: &mut DefaultHasher,
2639 error_format: ErrorOutputType,
2640 for_crate_hash: bool,
2641 ) {
2642 Hash::hash(&self.0.len(), hasher);
2643 for (key, val) in &self.0 {
2644 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2645 if !for_crate_hash {
2646 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2647 }
2648 }
2649 }
2650 }
2651
2652 // This is a stable hash because BTreeMap is a sorted container
stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )2653 crate fn stable_hash(
2654 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2655 hasher: &mut DefaultHasher,
2656 error_format: ErrorOutputType,
2657 for_crate_hash: bool,
2658 ) {
2659 for (key, sub_hash) in sub_hashes {
2660 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2661 // the keys, as they are just plain strings
2662 Hash::hash(&key.len(), hasher);
2663 Hash::hash(key, hasher);
2664 sub_hash.hash(hasher, error_format, for_crate_hash);
2665 }
2666 }
2667 }
2668