]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_session/src/config.rs
Inlining enabled by -mir-opt-level > 1 is incompatible with coverage
[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::match_is_nightly_build(matches) {
1312         early_error(
1313             ErrorOutputType::default(),
1314             &format!(
1315                 "edition {} is unstable and only \
1316                      available for nightly builds of rustc.",
1317                 edition,
1318             ),
1319         )
1320     }
1321
1322     edition
1323 }
1324
1325 fn check_debug_option_stability(
1326     debugging_opts: &DebuggingOptions,
1327     error_format: ErrorOutputType,
1328     json_rendered: HumanReadableErrorType,
1329 ) {
1330     if !debugging_opts.unstable_options {
1331         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1332             early_error(
1333                 ErrorOutputType::Json { pretty: false, json_rendered },
1334                 "`--error-format=pretty-json` is unstable",
1335             );
1336         }
1337         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1338             error_format
1339         {
1340             early_error(
1341                 ErrorOutputType::Json { pretty: false, json_rendered },
1342                 "`--error-format=human-annotate-rs` is unstable",
1343             );
1344         }
1345     }
1346 }
1347
1348 fn parse_output_types(
1349     debugging_opts: &DebuggingOptions,
1350     matches: &getopts::Matches,
1351     error_format: ErrorOutputType,
1352 ) -> OutputTypes {
1353     let mut output_types = BTreeMap::new();
1354     if !debugging_opts.parse_only {
1355         for list in matches.opt_strs("emit") {
1356             for output_type in list.split(',') {
1357                 let (shorthand, path) = match output_type.split_once('=') {
1358                     None => (output_type, None),
1359                     Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1360                 };
1361                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1362                     early_error(
1363                         error_format,
1364                         &format!(
1365                             "unknown emission type: `{}` - expected one of: {}",
1366                             shorthand,
1367                             OutputType::shorthands_display(),
1368                         ),
1369                     )
1370                 });
1371                 output_types.insert(output_type, path);
1372             }
1373         }
1374     };
1375     if output_types.is_empty() {
1376         output_types.insert(OutputType::Exe, None);
1377     }
1378     OutputTypes(output_types)
1379 }
1380
1381 fn should_override_cgus_and_disable_thinlto(
1382     output_types: &OutputTypes,
1383     matches: &getopts::Matches,
1384     error_format: ErrorOutputType,
1385     mut codegen_units: Option<usize>,
1386 ) -> (bool, Option<usize>) {
1387     let mut disable_thinlto = false;
1388     // Issue #30063: if user requests LLVM-related output to one
1389     // particular path, disable codegen-units.
1390     let incompatible: Vec<_> = output_types
1391         .0
1392         .iter()
1393         .map(|ot_path| ot_path.0)
1394         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1395         .map(|ot| ot.shorthand())
1396         .collect();
1397     if !incompatible.is_empty() {
1398         match codegen_units {
1399             Some(n) if n > 1 => {
1400                 if matches.opt_present("o") {
1401                     for ot in &incompatible {
1402                         early_warn(
1403                             error_format,
1404                             &format!(
1405                                 "`--emit={}` with `-o` incompatible with \
1406                                  `-C codegen-units=N` for N > 1",
1407                                 ot
1408                             ),
1409                         );
1410                     }
1411                     early_warn(error_format, "resetting to default -C codegen-units=1");
1412                     codegen_units = Some(1);
1413                     disable_thinlto = true;
1414                 }
1415             }
1416             _ => {
1417                 codegen_units = Some(1);
1418                 disable_thinlto = true;
1419             }
1420         }
1421     }
1422
1423     if codegen_units == Some(0) {
1424         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1425     }
1426
1427     (disable_thinlto, codegen_units)
1428 }
1429
1430 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1431     if debugging_opts.threads == 0 {
1432         early_error(error_format, "value for threads must be a positive non-zero integer");
1433     }
1434
1435     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1436         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1437     }
1438 }
1439
1440 fn collect_print_requests(
1441     cg: &mut CodegenOptions,
1442     dopts: &mut DebuggingOptions,
1443     matches: &getopts::Matches,
1444     error_format: ErrorOutputType,
1445 ) -> Vec<PrintRequest> {
1446     let mut prints = Vec::<PrintRequest>::new();
1447     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1448         prints.push(PrintRequest::TargetCPUs);
1449         cg.target_cpu = None;
1450     };
1451     if cg.target_feature == "help" {
1452         prints.push(PrintRequest::TargetFeatures);
1453         cg.target_feature = String::new();
1454     }
1455
1456     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1457         "crate-name" => PrintRequest::CrateName,
1458         "file-names" => PrintRequest::FileNames,
1459         "sysroot" => PrintRequest::Sysroot,
1460         "target-libdir" => PrintRequest::TargetLibdir,
1461         "cfg" => PrintRequest::Cfg,
1462         "target-list" => PrintRequest::TargetList,
1463         "target-cpus" => PrintRequest::TargetCPUs,
1464         "target-features" => PrintRequest::TargetFeatures,
1465         "relocation-models" => PrintRequest::RelocationModels,
1466         "code-models" => PrintRequest::CodeModels,
1467         "tls-models" => PrintRequest::TlsModels,
1468         "native-static-libs" => PrintRequest::NativeStaticLibs,
1469         "target-spec-json" => {
1470             if dopts.unstable_options {
1471                 PrintRequest::TargetSpec
1472             } else {
1473                 early_error(
1474                     error_format,
1475                     "the `-Z unstable-options` flag must also be passed to \
1476                      enable the target-spec-json print option",
1477                 );
1478             }
1479         }
1480         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1481     }));
1482
1483     prints
1484 }
1485
1486 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1487     match matches.opt_str("target") {
1488         Some(target) if target.ends_with(".json") => {
1489             let path = Path::new(&target);
1490             TargetTriple::from_path(&path).unwrap_or_else(|_| {
1491                 early_error(error_format, &format!("target file {:?} does not exist", path))
1492             })
1493         }
1494         Some(target) => TargetTriple::from_alias(target),
1495         _ => TargetTriple::from_triple(host_triple()),
1496     }
1497 }
1498
1499 fn parse_opt_level(
1500     matches: &getopts::Matches,
1501     cg: &CodegenOptions,
1502     error_format: ErrorOutputType,
1503 ) -> OptLevel {
1504     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1505     // to use them interchangeably. However, because they're technically different flags,
1506     // we need to work out manually which should take precedence if both are supplied (i.e.
1507     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1508     // comparing them. Note that if a flag is not found, its position will be `None`, which
1509     // always compared less than `Some(_)`.
1510     let max_o = matches.opt_positions("O").into_iter().max();
1511     let max_c = matches
1512         .opt_strs_pos("C")
1513         .into_iter()
1514         .flat_map(|(i, s)| {
1515             // NB: This can match a string without `=`.
1516             if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1517         })
1518         .max();
1519     if max_o > max_c {
1520         OptLevel::Default
1521     } else {
1522         match cg.opt_level.as_ref() {
1523             "0" => OptLevel::No,
1524             "1" => OptLevel::Less,
1525             "2" => OptLevel::Default,
1526             "3" => OptLevel::Aggressive,
1527             "s" => OptLevel::Size,
1528             "z" => OptLevel::SizeMin,
1529             arg => {
1530                 early_error(
1531                     error_format,
1532                     &format!(
1533                         "optimization level needs to be \
1534                             between 0-3, s or z (instead was `{}`)",
1535                         arg
1536                     ),
1537                 );
1538             }
1539         }
1540     }
1541 }
1542
1543 fn select_debuginfo(
1544     matches: &getopts::Matches,
1545     cg: &CodegenOptions,
1546     error_format: ErrorOutputType,
1547 ) -> DebugInfo {
1548     let max_g = matches.opt_positions("g").into_iter().max();
1549     let max_c = matches
1550         .opt_strs_pos("C")
1551         .into_iter()
1552         .flat_map(|(i, s)| {
1553             // NB: This can match a string without `=`.
1554             if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1555         })
1556         .max();
1557     if max_g > max_c {
1558         DebugInfo::Full
1559     } else {
1560         match cg.debuginfo {
1561             0 => DebugInfo::None,
1562             1 => DebugInfo::Limited,
1563             2 => DebugInfo::Full,
1564             arg => {
1565                 early_error(
1566                     error_format,
1567                     &format!(
1568                         "debug info level needs to be between \
1569                          0-2 (instead was `{}`)",
1570                         arg
1571                     ),
1572                 );
1573             }
1574         }
1575     }
1576 }
1577
1578 fn parse_libs(
1579     matches: &getopts::Matches,
1580     error_format: ErrorOutputType,
1581 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1582     matches
1583         .opt_strs("l")
1584         .into_iter()
1585         .map(|s| {
1586             // Parse string of the form "[KIND=]lib[:new_name]",
1587             // where KIND is one of "dylib", "framework", "static".
1588             let (name, kind) = match s.split_once('=') {
1589                 None => (s, NativeLibKind::Unspecified),
1590                 Some((kind, name)) => {
1591                     let kind = match kind {
1592                         "dylib" => NativeLibKind::Dylib,
1593                         "framework" => NativeLibKind::Framework,
1594                         "static" => NativeLibKind::StaticBundle,
1595                         "static-nobundle" => NativeLibKind::StaticNoBundle,
1596                         s => {
1597                             early_error(
1598                                 error_format,
1599                                 &format!(
1600                                     "unknown library kind `{}`, expected \
1601                                      one of dylib, framework, or static",
1602                                     s
1603                                 ),
1604                             );
1605                         }
1606                     };
1607                     (name.to_string(), kind)
1608                 }
1609             };
1610             if kind == NativeLibKind::StaticNoBundle
1611                 && !nightly_options::match_is_nightly_build(matches)
1612             {
1613                 early_error(
1614                     error_format,
1615                     "the library kind 'static-nobundle' is only \
1616                      accepted on the nightly compiler",
1617                 );
1618             }
1619             let (name, new_name) = match name.split_once(':') {
1620                 None => (name, None),
1621                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1622             };
1623             (name, new_name, kind)
1624         })
1625         .collect()
1626 }
1627
1628 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1629     match dopts.borrowck.as_ref() {
1630         "migrate" => BorrowckMode::Migrate,
1631         "mir" => BorrowckMode::Mir,
1632         m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1633     }
1634 }
1635
1636 pub fn parse_externs(
1637     matches: &getopts::Matches,
1638     debugging_opts: &DebuggingOptions,
1639     error_format: ErrorOutputType,
1640 ) -> Externs {
1641     let is_unstable_enabled = debugging_opts.unstable_options;
1642     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1643     for arg in matches.opt_strs("extern") {
1644         let (name, path) = match arg.split_once('=') {
1645             None => (arg, None),
1646             Some((name, path)) => (name.to_string(), Some(path.to_string())),
1647         };
1648         let (options, name) = match name.split_once(':') {
1649             None => (None, name),
1650             Some((opts, name)) => (Some(opts), name.to_string()),
1651         };
1652
1653         let entry = externs.entry(name.to_owned());
1654
1655         use std::collections::btree_map::Entry;
1656
1657         let entry = if let Some(path) = path {
1658             // --extern prelude_name=some_file.rlib
1659             match entry {
1660                 Entry::Vacant(vacant) => {
1661                     let files = BTreeSet::from_iter(iter::once(path));
1662                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1663                 }
1664                 Entry::Occupied(occupied) => {
1665                     let ext_ent = occupied.into_mut();
1666                     match ext_ent {
1667                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1668                             files.insert(path);
1669                         }
1670                         ExternEntry {
1671                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1672                             ..
1673                         } => {
1674                             // Exact paths take precedence over search directories.
1675                             let files = BTreeSet::from_iter(iter::once(path));
1676                             *location = ExternLocation::ExactPaths(files);
1677                         }
1678                     }
1679                     ext_ent
1680                 }
1681             }
1682         } else {
1683             // --extern prelude_name
1684             match entry {
1685                 Entry::Vacant(vacant) => {
1686                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1687                 }
1688                 Entry::Occupied(occupied) => {
1689                     // Ignore if already specified.
1690                     occupied.into_mut()
1691                 }
1692             }
1693         };
1694
1695         let mut is_private_dep = false;
1696         let mut add_prelude = true;
1697         if let Some(opts) = options {
1698             if !is_unstable_enabled {
1699                 early_error(
1700                     error_format,
1701                     "the `-Z unstable-options` flag must also be passed to \
1702                      enable `--extern options",
1703                 );
1704             }
1705             for opt in opts.split(',') {
1706                 match opt {
1707                     "priv" => is_private_dep = true,
1708                     "noprelude" => {
1709                         if let ExternLocation::ExactPaths(_) = &entry.location {
1710                             add_prelude = false;
1711                         } else {
1712                             early_error(
1713                                 error_format,
1714                                 "the `noprelude` --extern option requires a file path",
1715                             );
1716                         }
1717                     }
1718                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1719                 }
1720             }
1721         }
1722
1723         // Crates start out being not private, and go to being private `priv`
1724         // is specified.
1725         entry.is_private_dep |= is_private_dep;
1726         // If any flag is missing `noprelude`, then add to the prelude.
1727         entry.add_prelude |= add_prelude;
1728     }
1729     Externs(externs)
1730 }
1731
1732 fn parse_remap_path_prefix(
1733     matches: &getopts::Matches,
1734     error_format: ErrorOutputType,
1735 ) -> Vec<(PathBuf, PathBuf)> {
1736     matches
1737         .opt_strs("remap-path-prefix")
1738         .into_iter()
1739         .map(|remap| match remap.rsplit_once('=') {
1740             None => early_error(
1741                 error_format,
1742                 "--remap-path-prefix must contain '=' between FROM and TO",
1743             ),
1744             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1745         })
1746         .collect()
1747 }
1748
1749 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1750     let color = parse_color(matches);
1751
1752     let edition = parse_crate_edition(matches);
1753
1754     let (json_rendered, json_artifact_notifications) = parse_json(matches);
1755
1756     let error_format = parse_error_format(matches, color, json_rendered);
1757
1758     let unparsed_crate_types = matches.opt_strs("crate-type");
1759     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1760         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1761
1762     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1763
1764     let mut debugging_opts = build_debugging_options(matches, error_format);
1765     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1766
1767     let output_types = parse_output_types(&debugging_opts, matches, error_format);
1768
1769     let mut cg = build_codegen_options(matches, error_format);
1770     let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1771         &output_types,
1772         matches,
1773         error_format,
1774         cg.codegen_units,
1775     );
1776
1777     check_thread_count(&debugging_opts, error_format);
1778
1779     let incremental = cg.incremental.as_ref().map(PathBuf::from);
1780
1781     if debugging_opts.profile && incremental.is_some() {
1782         early_error(
1783             error_format,
1784             "can't instrument with gcov profiling when compiling incrementally",
1785         );
1786     }
1787     if debugging_opts.profile {
1788         match codegen_units {
1789             Some(1) => {}
1790             None => codegen_units = Some(1),
1791             Some(_) => early_error(
1792                 error_format,
1793                 "can't instrument with gcov profiling with multiple codegen units",
1794             ),
1795         }
1796     }
1797
1798     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1799         early_error(
1800             error_format,
1801             "options `-C profile-generate` and `-C profile-use` are exclusive",
1802         );
1803     }
1804
1805     if debugging_opts.instrument_coverage {
1806         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1807             early_error(
1808                 error_format,
1809                 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1810                 or `-C profile-generate`",
1811             );
1812         }
1813
1814         // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1815         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1816         // multiple runs, including some changes to source code; so mangled names must be consistent
1817         // across compilations.
1818         match debugging_opts.symbol_mangling_version {
1819             None => {
1820                 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1821             }
1822             Some(SymbolManglingVersion::Legacy) => {
1823                 early_warn(
1824                     error_format,
1825                     "-Z instrument-coverage requires symbol mangling version `v0`, \
1826                     but `-Z symbol-mangling-version=legacy` was specified",
1827                 );
1828             }
1829             Some(SymbolManglingVersion::V0) => {}
1830         }
1831
1832         if debugging_opts.mir_opt_level > 1 {
1833             // Functions inlined during MIR transform can, at best, make it impossible to
1834             // effectively cover inlined functions, and, at worst, break coverage map generation
1835             // during LLVM codegen. For example, function counter IDs are only unique within a
1836             // function. Inlining after these counters are injected can produce duplicate counters,
1837             // resulting in an invalid coverage map (and ICE); so this option combination is not
1838             // allowed.
1839             early_warn(
1840                 error_format,
1841                 &format!(
1842                     "`-Z mir-opt-level={}` (or any level > 1) enables function inlining, which \
1843                     is incompatible with `-Z instrument-coverage`. Inlining will be disabled.",
1844                     debugging_opts.mir_opt_level,
1845                 ),
1846             );
1847         }
1848     }
1849
1850     if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1851         debugging_opts.graphviz_font = graphviz_font;
1852     }
1853
1854     if !cg.embed_bitcode {
1855         match cg.lto {
1856             LtoCli::No | LtoCli::Unspecified => {}
1857             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1858                 error_format,
1859                 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1860             ),
1861         }
1862     }
1863
1864     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1865
1866     let cg = cg;
1867
1868     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1869     let target_triple = parse_target_triple(matches, error_format);
1870     let opt_level = parse_opt_level(matches, &cg, error_format);
1871     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1872     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1873     // for more details.
1874     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1875     let debuginfo = select_debuginfo(matches, &cg, error_format);
1876
1877     let mut search_paths = vec![];
1878     for s in &matches.opt_strs("L") {
1879         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1880     }
1881
1882     let libs = parse_libs(matches, error_format);
1883
1884     let test = matches.opt_present("test");
1885
1886     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1887
1888     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1889         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1890     }
1891
1892     let externs = parse_externs(matches, &debugging_opts, error_format);
1893
1894     let crate_name = matches.opt_str("crate-name");
1895
1896     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1897
1898     let pretty = parse_pretty(matches, &debugging_opts, error_format);
1899
1900     Options {
1901         crate_types,
1902         optimize: opt_level,
1903         debuginfo,
1904         lint_opts,
1905         lint_cap,
1906         describe_lints,
1907         output_types,
1908         search_paths,
1909         maybe_sysroot: sysroot_opt,
1910         target_triple,
1911         test,
1912         incremental,
1913         debugging_opts,
1914         prints,
1915         borrowck_mode,
1916         cg,
1917         error_format,
1918         externs,
1919         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
1920         crate_name,
1921         alt_std_name: None,
1922         libs,
1923         debug_assertions,
1924         actually_rustdoc: false,
1925         trimmed_def_paths: TrimmedDefPaths::default(),
1926         cli_forced_codegen_units: codegen_units,
1927         cli_forced_thinlto_off: disable_thinlto,
1928         remap_path_prefix,
1929         edition,
1930         json_artifact_notifications,
1931         pretty,
1932     }
1933 }
1934
1935 fn parse_pretty(
1936     matches: &getopts::Matches,
1937     debugging_opts: &DebuggingOptions,
1938     efmt: ErrorOutputType,
1939 ) -> Option<PpMode> {
1940     let pretty = if debugging_opts.unstable_options {
1941         matches.opt_default("pretty", "normal").map(|a| {
1942             // stable pretty-print variants only
1943             parse_pretty_inner(efmt, &a, false)
1944         })
1945     } else {
1946         None
1947     };
1948
1949     return if pretty.is_none() {
1950         debugging_opts.unpretty.as_ref().map(|a| {
1951             // extended with unstable pretty-print variants
1952             parse_pretty_inner(efmt, &a, true)
1953         })
1954     } else {
1955         pretty
1956     };
1957
1958     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1959         use PpMode::*;
1960         use PpSourceMode::*;
1961         let first = match (name, extended) {
1962             ("normal", _) => PpmSource(PpmNormal),
1963             ("identified", _) => PpmSource(PpmIdentified),
1964             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1965             ("expanded", _) => PpmSource(PpmExpanded),
1966             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1967             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1968             ("hir", true) => PpmHir(PpmNormal),
1969             ("hir,identified", true) => PpmHir(PpmIdentified),
1970             ("hir,typed", true) => PpmHir(PpmTyped),
1971             ("hir-tree", true) => PpmHirTree(PpmNormal),
1972             ("mir", true) => PpmMir,
1973             ("mir-cfg", true) => PpmMirCFG,
1974             _ => {
1975                 if extended {
1976                     early_error(
1977                         efmt,
1978                         &format!(
1979                             "argument to `unpretty` must be one of `normal`, \
1980                                         `expanded`, `identified`, `expanded,identified`, \
1981                                         `expanded,hygiene`, `everybody_loops`, \
1982                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1983                                         `mir` or `mir-cfg`; got {}",
1984                             name
1985                         ),
1986                     );
1987                 } else {
1988                     early_error(
1989                         efmt,
1990                         &format!(
1991                             "argument to `pretty` must be one of `normal`, \
1992                                         `expanded`, `identified`, or `expanded,identified`; got {}",
1993                             name
1994                         ),
1995                     );
1996                 }
1997             }
1998         };
1999         tracing::debug!("got unpretty option: {:?}", first);
2000         first
2001     }
2002 }
2003
2004 pub fn make_crate_type_option() -> RustcOptGroup {
2005     opt::multi_s(
2006         "",
2007         "crate-type",
2008         "Comma separated list of types of crates
2009                                 for the compiler to emit",
2010         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2011     )
2012 }
2013
2014 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2015     let mut crate_types: Vec<CrateType> = Vec::new();
2016     for unparsed_crate_type in &list_list {
2017         for part in unparsed_crate_type.split(',') {
2018             let new_part = match part {
2019                 "lib" => default_lib_output(),
2020                 "rlib" => CrateType::Rlib,
2021                 "staticlib" => CrateType::Staticlib,
2022                 "dylib" => CrateType::Dylib,
2023                 "cdylib" => CrateType::Cdylib,
2024                 "bin" => CrateType::Executable,
2025                 "proc-macro" => CrateType::ProcMacro,
2026                 _ => return Err(format!("unknown crate type: `{}`", part)),
2027             };
2028             if !crate_types.contains(&new_part) {
2029                 crate_types.push(new_part)
2030             }
2031         }
2032     }
2033
2034     Ok(crate_types)
2035 }
2036
2037 pub mod nightly_options {
2038     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2039     use crate::early_error;
2040     use rustc_feature::UnstableFeatures;
2041
2042     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2043         match_is_nightly_build(matches)
2044             && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2045     }
2046
2047     pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2048         is_nightly_build(matches.opt_str("crate-name").as_deref())
2049     }
2050
2051     pub fn is_nightly_build(krate: Option<&str>) -> bool {
2052         UnstableFeatures::from_environment(krate).is_nightly_build()
2053     }
2054
2055     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2056         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2057         let really_allows_unstable_options = match_is_nightly_build(matches);
2058
2059         for opt in flags.iter() {
2060             if opt.stability == OptionStability::Stable {
2061                 continue;
2062             }
2063             if !matches.opt_present(opt.name) {
2064                 continue;
2065             }
2066             if opt.name != "Z" && !has_z_unstable_option {
2067                 early_error(
2068                     ErrorOutputType::default(),
2069                     &format!(
2070                         "the `-Z unstable-options` flag must also be passed to enable \
2071                          the flag `{}`",
2072                         opt.name
2073                     ),
2074                 );
2075             }
2076             if really_allows_unstable_options {
2077                 continue;
2078             }
2079             match opt.stability {
2080                 OptionStability::Unstable => {
2081                     let msg = format!(
2082                         "the option `{}` is only accepted on the \
2083                          nightly compiler",
2084                         opt.name
2085                     );
2086                     early_error(ErrorOutputType::default(), &msg);
2087                 }
2088                 OptionStability::Stable => {}
2089             }
2090         }
2091     }
2092 }
2093
2094 impl fmt::Display for CrateType {
2095     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2096         match *self {
2097             CrateType::Executable => "bin".fmt(f),
2098             CrateType::Dylib => "dylib".fmt(f),
2099             CrateType::Rlib => "rlib".fmt(f),
2100             CrateType::Staticlib => "staticlib".fmt(f),
2101             CrateType::Cdylib => "cdylib".fmt(f),
2102             CrateType::ProcMacro => "proc-macro".fmt(f),
2103         }
2104     }
2105 }
2106
2107 #[derive(Copy, Clone, PartialEq, Debug)]
2108 pub enum PpSourceMode {
2109     PpmNormal,
2110     PpmEveryBodyLoops,
2111     PpmExpanded,
2112     PpmIdentified,
2113     PpmExpandedIdentified,
2114     PpmExpandedHygiene,
2115     PpmTyped,
2116 }
2117
2118 #[derive(Copy, Clone, PartialEq, Debug)]
2119 pub enum PpMode {
2120     PpmSource(PpSourceMode),
2121     PpmHir(PpSourceMode),
2122     PpmHirTree(PpSourceMode),
2123     PpmMir,
2124     PpmMirCFG,
2125 }
2126
2127 impl PpMode {
2128     pub fn needs_ast_map(&self) -> bool {
2129         use PpMode::*;
2130         use PpSourceMode::*;
2131         match *self {
2132             PpmSource(PpmNormal | PpmIdentified) => false,
2133
2134             PpmSource(
2135                 PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
2136             )
2137             | PpmHir(_)
2138             | PpmHirTree(_)
2139             | PpmMir
2140             | PpmMirCFG => true,
2141             PpmSource(PpmTyped) => panic!("invalid state"),
2142         }
2143     }
2144
2145     pub fn needs_analysis(&self) -> bool {
2146         use PpMode::*;
2147         matches!(*self, PpmMir | PpmMirCFG)
2148     }
2149 }
2150
2151 /// Command-line arguments passed to the compiler have to be incorporated with
2152 /// the dependency tracking system for incremental compilation. This module
2153 /// provides some utilities to make this more convenient.
2154 ///
2155 /// The values of all command-line arguments that are relevant for dependency
2156 /// tracking are hashed into a single value that determines whether the
2157 /// incremental compilation cache can be re-used or not. This hashing is done
2158 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2159 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2160 /// the hash of which is order dependent, but we might not want the order of
2161 /// arguments to make a difference for the hash).
2162 ///
2163 /// However, since the value provided by `Hash::hash` often *is* suitable,
2164 /// especially for primitive types, there is the
2165 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2166 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2167 /// we have an opt-in scheme here, so one is hopefully forced to think about
2168 /// how the hash should be calculated when adding a new command-line argument.
2169 crate mod dep_tracking {
2170     use super::{
2171         CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2172         OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2173         SymbolManglingVersion, TrimmedDefPaths,
2174     };
2175     use crate::lint;
2176     use crate::utils::NativeLibKind;
2177     use rustc_feature::UnstableFeatures;
2178     use rustc_span::edition::Edition;
2179     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2180     use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2181     use std::collections::hash_map::DefaultHasher;
2182     use std::collections::BTreeMap;
2183     use std::hash::Hash;
2184     use std::path::PathBuf;
2185
2186     pub trait DepTrackingHash {
2187         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2188     }
2189
2190     macro_rules! impl_dep_tracking_hash_via_hash {
2191         ($t:ty) => {
2192             impl DepTrackingHash for $t {
2193                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2194                     Hash::hash(self, hasher);
2195                 }
2196             }
2197         };
2198     }
2199
2200     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2201         ($t:ty) => {
2202             impl DepTrackingHash for Vec<$t> {
2203                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2204                     let mut elems: Vec<&$t> = self.iter().collect();
2205                     elems.sort();
2206                     Hash::hash(&elems.len(), hasher);
2207                     for (index, elem) in elems.iter().enumerate() {
2208                         Hash::hash(&index, hasher);
2209                         DepTrackingHash::hash(*elem, hasher, error_format);
2210                     }
2211                 }
2212             }
2213         };
2214     }
2215
2216     impl_dep_tracking_hash_via_hash!(bool);
2217     impl_dep_tracking_hash_via_hash!(usize);
2218     impl_dep_tracking_hash_via_hash!(u64);
2219     impl_dep_tracking_hash_via_hash!(String);
2220     impl_dep_tracking_hash_via_hash!(PathBuf);
2221     impl_dep_tracking_hash_via_hash!(lint::Level);
2222     impl_dep_tracking_hash_via_hash!(Option<bool>);
2223     impl_dep_tracking_hash_via_hash!(Option<usize>);
2224     impl_dep_tracking_hash_via_hash!(Option<String>);
2225     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2226     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2227     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2228     impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2229     impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2230     impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2231     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2232     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2233     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2234     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2235     impl_dep_tracking_hash_via_hash!(CrateType);
2236     impl_dep_tracking_hash_via_hash!(MergeFunctions);
2237     impl_dep_tracking_hash_via_hash!(PanicStrategy);
2238     impl_dep_tracking_hash_via_hash!(RelroLevel);
2239     impl_dep_tracking_hash_via_hash!(Passes);
2240     impl_dep_tracking_hash_via_hash!(OptLevel);
2241     impl_dep_tracking_hash_via_hash!(LtoCli);
2242     impl_dep_tracking_hash_via_hash!(DebugInfo);
2243     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2244     impl_dep_tracking_hash_via_hash!(OutputTypes);
2245     impl_dep_tracking_hash_via_hash!(NativeLibKind);
2246     impl_dep_tracking_hash_via_hash!(SanitizerSet);
2247     impl_dep_tracking_hash_via_hash!(CFGuard);
2248     impl_dep_tracking_hash_via_hash!(TargetTriple);
2249     impl_dep_tracking_hash_via_hash!(Edition);
2250     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2251     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2252     impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2253     impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2254     impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2255
2256     impl_dep_tracking_hash_for_sortable_vec_of!(String);
2257     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2258     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2259     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2260     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2261     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2262
2263     impl<T1, T2> DepTrackingHash for (T1, T2)
2264     where
2265         T1: DepTrackingHash,
2266         T2: DepTrackingHash,
2267     {
2268         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2269             Hash::hash(&0, hasher);
2270             DepTrackingHash::hash(&self.0, hasher, error_format);
2271             Hash::hash(&1, hasher);
2272             DepTrackingHash::hash(&self.1, hasher, error_format);
2273         }
2274     }
2275
2276     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2277     where
2278         T1: DepTrackingHash,
2279         T2: DepTrackingHash,
2280         T3: DepTrackingHash,
2281     {
2282         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2283             Hash::hash(&0, hasher);
2284             DepTrackingHash::hash(&self.0, hasher, error_format);
2285             Hash::hash(&1, hasher);
2286             DepTrackingHash::hash(&self.1, hasher, error_format);
2287             Hash::hash(&2, hasher);
2288             DepTrackingHash::hash(&self.2, hasher, error_format);
2289         }
2290     }
2291
2292     // This is a stable hash because BTreeMap is a sorted container
2293     pub fn stable_hash(
2294         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2295         hasher: &mut DefaultHasher,
2296         error_format: ErrorOutputType,
2297     ) {
2298         for (key, sub_hash) in sub_hashes {
2299             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2300             // the keys, as they are just plain strings
2301             Hash::hash(&key.len(), hasher);
2302             Hash::hash(key, hasher);
2303             sub_hash.hash(hasher, error_format);
2304         }
2305     }
2306 }