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