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