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