]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_session/src/config.rs
Rollup merge of #84803 - jyn514:duplicate-macros, r=petrochenkov
[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, Debug)]
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, Debug)]
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             real_rust_source_base_dir: None,
706             edition: DEFAULT_EDITION,
707             json_artifact_notifications: false,
708             json_unused_externs: false,
709             pretty: None,
710         }
711     }
712 }
713
714 impl Options {
715     /// Returns `true` if there is a reason to build the dep graph.
716     pub fn build_dep_graph(&self) -> bool {
717         self.incremental.is_some()
718             || self.debugging_opts.dump_dep_graph
719             || self.debugging_opts.query_dep_graph
720     }
721
722     pub fn file_path_mapping(&self) -> FilePathMapping {
723         FilePathMapping::new(self.remap_path_prefix.clone())
724     }
725
726     /// Returns `true` if there will be an output file generated.
727     pub fn will_create_output_file(&self) -> bool {
728         !self.debugging_opts.parse_only && // The file is just being parsed
729             !self.debugging_opts.ls // The file is just being queried
730     }
731
732     #[inline]
733     pub fn share_generics(&self) -> bool {
734         match self.debugging_opts.share_generics {
735             Some(setting) => setting,
736             None => match self.optimize {
737                 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
738                 OptLevel::Default | OptLevel::Aggressive => false,
739             },
740         }
741     }
742 }
743
744 impl DebuggingOptions {
745     pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
746         HandlerFlags {
747             can_emit_warnings,
748             treat_err_as_bug: self.treat_err_as_bug,
749             dont_buffer_diagnostics: self.dont_buffer_diagnostics,
750             report_delayed_bugs: self.report_delayed_bugs,
751             macro_backtrace: self.macro_backtrace,
752             deduplicate_diagnostics: self.deduplicate_diagnostics,
753         }
754     }
755
756     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
757         self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
758     }
759 }
760
761 // The type of entry function, so users can have their own entry functions
762 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
763 pub enum EntryFnType {
764     Main,
765     Start,
766 }
767
768 impl_stable_hash_via_hash!(EntryFnType);
769
770 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
771 pub enum CrateType {
772     Executable,
773     Dylib,
774     Rlib,
775     Staticlib,
776     Cdylib,
777     ProcMacro,
778 }
779
780 impl_stable_hash_via_hash!(CrateType);
781
782 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
783 pub enum Passes {
784     Some(Vec<String>),
785     All,
786 }
787
788 impl Passes {
789     pub fn is_empty(&self) -> bool {
790         match *self {
791             Passes::Some(ref v) => v.is_empty(),
792             Passes::All => false,
793         }
794     }
795 }
796
797 pub const fn default_lib_output() -> CrateType {
798     CrateType::Rlib
799 }
800
801 fn default_configuration(sess: &Session) -> CrateConfig {
802     let end = &sess.target.endian;
803     let arch = &sess.target.arch;
804     let wordsz = sess.target.pointer_width.to_string();
805     let os = &sess.target.os;
806     let env = &sess.target.env;
807     let vendor = &sess.target.vendor;
808     let min_atomic_width = sess.target.min_atomic_width();
809     let max_atomic_width = sess.target.max_atomic_width();
810     let atomic_cas = sess.target.atomic_cas;
811     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
812         sess.fatal(&err);
813     });
814
815     let mut ret = FxHashSet::default();
816     ret.reserve(6); // the minimum number of insertions
817     // Target bindings.
818     ret.insert((sym::target_os, Some(Symbol::intern(os))));
819     for fam in &sess.target.families {
820         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
821         if fam == "windows" {
822             ret.insert((sym::windows, None));
823         } else if fam == "unix" {
824             ret.insert((sym::unix, None));
825         }
826     }
827     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
828     ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
829     ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
830     ret.insert((sym::target_env, Some(Symbol::intern(env))));
831     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
832     if sess.target.has_elf_tls {
833         ret.insert((sym::target_thread_local, None));
834     }
835     for &(i, align) in &[
836         (8, layout.i8_align.abi),
837         (16, layout.i16_align.abi),
838         (32, layout.i32_align.abi),
839         (64, layout.i64_align.abi),
840         (128, layout.i128_align.abi),
841     ] {
842         if i >= min_atomic_width && i <= max_atomic_width {
843             let mut insert_atomic = |s, align: Align| {
844                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
845                 if atomic_cas {
846                     ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
847                 }
848                 if align.bits() == i {
849                     ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
850                 }
851             };
852             let s = i.to_string();
853             insert_atomic(&s, align);
854             if s == wordsz {
855                 insert_atomic("ptr", layout.pointer_align.abi);
856             }
857         }
858     }
859
860     let panic_strategy = sess.panic_strategy();
861     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
862
863     for s in sess.opts.debugging_opts.sanitizer {
864         let symbol = Symbol::intern(&s.to_string());
865         ret.insert((sym::sanitize, Some(symbol)));
866     }
867
868     if sess.opts.debug_assertions {
869         ret.insert((sym::debug_assertions, None));
870     }
871     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
872         ret.insert((sym::proc_macro, None));
873     }
874     ret
875 }
876
877 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
878 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
879 /// but the symbol interner is not yet set up then, so we must convert it later.
880 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
881     cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
882 }
883
884 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
885     // Combine the configuration requested by the session (command line) with
886     // some default and generated configuration items.
887     let default_cfg = default_configuration(sess);
888     // If the user wants a test runner, then add the test cfg.
889     if sess.opts.test {
890         user_cfg.insert((sym::test, None));
891     }
892     user_cfg.extend(default_cfg.iter().cloned());
893     user_cfg
894 }
895
896 pub(super) fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
897     let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
898     let target = target_result.unwrap_or_else(|e| {
899         early_error(
900             opts.error_format,
901             &format!(
902                 "Error loading target specification: {}. \
903                  Run `rustc --print target-list` for a list of built-in targets",
904                 e
905             ),
906         )
907     });
908
909     if !matches!(target.pointer_width, 16 | 32 | 64) {
910         early_error(
911             opts.error_format,
912             &format!(
913                 "target specification was invalid: \
914              unrecognized target-pointer-width {}",
915                 target.pointer_width
916             ),
917         )
918     }
919
920     target
921 }
922
923 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
924 pub enum OptionStability {
925     Stable,
926     Unstable,
927 }
928
929 pub struct RustcOptGroup {
930     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
931     pub name: &'static str,
932     pub stability: OptionStability,
933 }
934
935 impl RustcOptGroup {
936     pub fn is_stable(&self) -> bool {
937         self.stability == OptionStability::Stable
938     }
939
940     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
941     where
942         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
943     {
944         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
945     }
946
947     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
948     where
949         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
950     {
951         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
952     }
953 }
954
955 // The `opt` local module holds wrappers around the `getopts` API that
956 // adds extra rustc-specific metadata to each option; such metadata
957 // is exposed by .  The public
958 // functions below ending with `_u` are the functions that return
959 // *unstable* options, i.e., options that are only enabled when the
960 // user also passes the `-Z unstable-options` debugging flag.
961 mod opt {
962     // The `fn flag*` etc below are written so that we can use them
963     // in the future; do not warn about them not being used right now.
964     #![allow(dead_code)]
965
966     use super::RustcOptGroup;
967
968     pub type R = RustcOptGroup;
969     pub type S = &'static str;
970
971     fn stable<F>(name: S, f: F) -> R
972     where
973         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
974     {
975         RustcOptGroup::stable(name, f)
976     }
977
978     fn unstable<F>(name: S, f: F) -> R
979     where
980         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
981     {
982         RustcOptGroup::unstable(name, f)
983     }
984
985     fn longer(a: S, b: S) -> S {
986         if a.len() > b.len() { a } else { b }
987     }
988
989     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
990         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
991     }
992     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
993         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
994     }
995     pub fn flag_s(a: S, b: S, c: S) -> R {
996         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
997     }
998     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
999         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1000     }
1001
1002     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1003         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1004     }
1005     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1006         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1007     }
1008 }
1009
1010 /// Returns the "short" subset of the rustc command line options,
1011 /// including metadata for each option, such as whether the option is
1012 /// part of the stable long-term interface for rustc.
1013 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1014     vec![
1015         opt::flag_s("h", "help", "Display this message"),
1016         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1017         opt::multi_s(
1018             "L",
1019             "",
1020             "Add a directory to the library search path. The
1021                              optional KIND can be one of dependency, crate, native,
1022                              framework, or all (the default).",
1023             "[KIND=]PATH",
1024         ),
1025         opt::multi_s(
1026             "l",
1027             "",
1028             "Link the generated crate(s) to the specified native
1029                              library NAME. The optional KIND can be one of
1030                              static, framework, or dylib (the default).",
1031             "[KIND=]NAME",
1032         ),
1033         make_crate_type_option(),
1034         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1035         opt::opt_s(
1036             "",
1037             "edition",
1038             "Specify which edition of the compiler to use when compiling code.",
1039             EDITION_NAME_LIST,
1040         ),
1041         opt::multi_s(
1042             "",
1043             "emit",
1044             "Comma separated list of types of output for \
1045              the compiler to emit",
1046             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1047         ),
1048         opt::multi_s(
1049             "",
1050             "print",
1051             "Compiler information to print on stdout",
1052             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1053              target-cpus|target-features|relocation-models|\
1054              code-models|tls-models|target-spec-json|native-static-libs]",
1055         ),
1056         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1057         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1058         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1059         opt::opt_s(
1060             "",
1061             "out-dir",
1062             "Write output to compiler-chosen filename \
1063              in <dir>",
1064             "DIR",
1065         ),
1066         opt::opt_s(
1067             "",
1068             "explain",
1069             "Provide a detailed explanation of an error \
1070              message",
1071             "OPT",
1072         ),
1073         opt::flag_s("", "test", "Build a test harness"),
1074         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1075         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1076         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1077         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1078         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1079         opt::multi_s(
1080             "",
1081             "cap-lints",
1082             "Set the most restrictive lint level. \
1083              More restrictive lints are capped at this \
1084              level",
1085             "LEVEL",
1086         ),
1087         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1088         opt::flag_s("V", "version", "Print version info and exit"),
1089         opt::flag_s("v", "verbose", "Use verbose output"),
1090     ]
1091 }
1092
1093 /// Returns all rustc command line options, including metadata for
1094 /// each option, such as whether the option is part of the stable
1095 /// long-term interface for rustc.
1096 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1097     let mut opts = rustc_short_optgroups();
1098     opts.extend(vec![
1099         opt::multi_s(
1100             "",
1101             "extern",
1102             "Specify where an external rust library is located",
1103             "NAME[=PATH]",
1104         ),
1105         opt::multi_s(
1106             "",
1107             "extern-location",
1108             "Location where an external crate dependency is specified",
1109             "NAME=LOCATION",
1110         ),
1111         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1112         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1113         opt::opt_s(
1114             "",
1115             "error-format",
1116             "How errors and other messages are produced",
1117             "human|json|short",
1118         ),
1119         opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1120         opt::opt_s(
1121             "",
1122             "color",
1123             "Configure coloring of output:
1124                                  auto   = colorize, if output goes to a tty (default);
1125                                  always = always colorize output;
1126                                  never  = never colorize output",
1127             "auto|always|never",
1128         ),
1129         opt::opt(
1130             "",
1131             "pretty",
1132             "Pretty-print the input instead of compiling;
1133                   valid types are: `normal` (un-annotated source),
1134                   `expanded` (crates expanded), or
1135                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1136             "TYPE",
1137         ),
1138         opt::multi_s(
1139             "",
1140             "remap-path-prefix",
1141             "Remap source names in all output (compiler messages and output files)",
1142             "FROM=TO",
1143         ),
1144     ]);
1145     opts
1146 }
1147
1148 pub fn get_cmd_lint_options(
1149     matches: &getopts::Matches,
1150     error_format: ErrorOutputType,
1151 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1152     let mut lint_opts_with_position = vec![];
1153     let mut describe_lints = false;
1154
1155     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1156         for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1157             let arg_pos = if let lint::Forbid = level {
1158                 // HACK: forbid is always specified last, so it can't be overridden.
1159                 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1160                 // fixed and `forbid` works as expected.
1161                 usize::MAX
1162             } else {
1163                 passed_arg_pos
1164             };
1165             if lint_name == "help" {
1166                 describe_lints = true;
1167             } else {
1168                 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1169             }
1170         }
1171     }
1172
1173     lint_opts_with_position.sort_by_key(|x| x.0);
1174     let lint_opts = lint_opts_with_position
1175         .iter()
1176         .cloned()
1177         .map(|(_, lint_name, level)| (lint_name, level))
1178         .collect();
1179
1180     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1181         lint::Level::from_str(&cap)
1182             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1183     });
1184     (lint_opts, describe_lints, lint_cap)
1185 }
1186
1187 /// Parses the `--color` flag.
1188 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1189     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1190         Some("auto") => ColorConfig::Auto,
1191         Some("always") => ColorConfig::Always,
1192         Some("never") => ColorConfig::Never,
1193
1194         None => ColorConfig::Auto,
1195
1196         Some(arg) => early_error(
1197             ErrorOutputType::default(),
1198             &format!(
1199                 "argument for `--color` must be auto, \
1200                  always or never (instead was `{}`)",
1201                 arg
1202             ),
1203         ),
1204     }
1205 }
1206
1207 /// Possible json config files
1208 pub struct JsonConfig {
1209     pub json_rendered: HumanReadableErrorType,
1210     pub json_artifact_notifications: bool,
1211     pub json_unused_externs: bool,
1212 }
1213
1214 /// Parse the `--json` flag.
1215 ///
1216 /// The first value returned is how to render JSON diagnostics, and the second
1217 /// is whether or not artifact notifications are enabled.
1218 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1219     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1220         HumanReadableErrorType::Default;
1221     let mut json_color = ColorConfig::Never;
1222     let mut json_artifact_notifications = false;
1223     let mut json_unused_externs = false;
1224     for option in matches.opt_strs("json") {
1225         // For now conservatively forbid `--color` with `--json` since `--json`
1226         // won't actually be emitting any colors and anything colorized is
1227         // embedded in a diagnostic message anyway.
1228         if matches.opt_str("color").is_some() {
1229             early_error(
1230                 ErrorOutputType::default(),
1231                 "cannot specify the `--color` option with `--json`",
1232             );
1233         }
1234
1235         for sub_option in option.split(',') {
1236             match sub_option {
1237                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1238                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1239                 "artifacts" => json_artifact_notifications = true,
1240                 "unused-externs" => json_unused_externs = true,
1241                 s => early_error(
1242                     ErrorOutputType::default(),
1243                     &format!("unknown `--json` option `{}`", s),
1244                 ),
1245             }
1246         }
1247     }
1248
1249     JsonConfig {
1250         json_rendered: json_rendered(json_color),
1251         json_artifact_notifications,
1252         json_unused_externs,
1253     }
1254 }
1255
1256 /// Parses the `--error-format` flag.
1257 pub fn parse_error_format(
1258     matches: &getopts::Matches,
1259     color: ColorConfig,
1260     json_rendered: HumanReadableErrorType,
1261 ) -> ErrorOutputType {
1262     // We need the `opts_present` check because the driver will send us Matches
1263     // with only stable options if no unstable options are used. Since error-format
1264     // is unstable, it will not be present. We have to use `opts_present` not
1265     // `opt_present` because the latter will panic.
1266     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1267         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1268             None | Some("human") => {
1269                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1270             }
1271             Some("human-annotate-rs") => {
1272                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1273             }
1274             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1275             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1276             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1277
1278             Some(arg) => early_error(
1279                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1280                 &format!(
1281                     "argument for `--error-format` must be `human`, `json` or \
1282                      `short` (instead was `{}`)",
1283                     arg
1284                 ),
1285             ),
1286         }
1287     } else {
1288         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1289     };
1290
1291     match error_format {
1292         ErrorOutputType::Json { .. } => {}
1293
1294         // Conservatively require that the `--json` argument is coupled with
1295         // `--error-format=json`. This means that `--json` is specified we
1296         // should actually be emitting JSON blobs.
1297         _ if !matches.opt_strs("json").is_empty() => {
1298             early_error(
1299                 ErrorOutputType::default(),
1300                 "using `--json` requires also using `--error-format=json`",
1301             );
1302         }
1303
1304         _ => {}
1305     }
1306
1307     error_format
1308 }
1309
1310 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1311     let edition = match matches.opt_str("edition") {
1312         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1313             early_error(
1314                 ErrorOutputType::default(),
1315                 &format!(
1316                     "argument for `--edition` must be one of: \
1317                      {}. (instead was `{}`)",
1318                     EDITION_NAME_LIST, arg
1319                 ),
1320             )
1321         }),
1322         None => DEFAULT_EDITION,
1323     };
1324
1325     if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1326         let is_nightly = nightly_options::match_is_nightly_build(matches);
1327         let msg = if !is_nightly {
1328             format!(
1329                 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1330                 edition, LATEST_STABLE_EDITION
1331             )
1332         } else {
1333             format!("edition {} is unstable and only available with -Z unstable-options", edition)
1334         };
1335         early_error(ErrorOutputType::default(), &msg)
1336     }
1337
1338     edition
1339 }
1340
1341 fn check_debug_option_stability(
1342     debugging_opts: &DebuggingOptions,
1343     error_format: ErrorOutputType,
1344     json_rendered: HumanReadableErrorType,
1345 ) {
1346     if !debugging_opts.unstable_options {
1347         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1348             early_error(
1349                 ErrorOutputType::Json { pretty: false, json_rendered },
1350                 "`--error-format=pretty-json` is unstable",
1351             );
1352         }
1353         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1354             error_format
1355         {
1356             early_error(
1357                 ErrorOutputType::Json { pretty: false, json_rendered },
1358                 "`--error-format=human-annotate-rs` is unstable",
1359             );
1360         }
1361     }
1362 }
1363
1364 fn parse_output_types(
1365     debugging_opts: &DebuggingOptions,
1366     matches: &getopts::Matches,
1367     error_format: ErrorOutputType,
1368 ) -> OutputTypes {
1369     let mut output_types = BTreeMap::new();
1370     if !debugging_opts.parse_only {
1371         for list in matches.opt_strs("emit") {
1372             for output_type in list.split(',') {
1373                 let (shorthand, path) = match output_type.split_once('=') {
1374                     None => (output_type, None),
1375                     Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1376                 };
1377                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1378                     early_error(
1379                         error_format,
1380                         &format!(
1381                             "unknown emission type: `{}` - expected one of: {}",
1382                             shorthand,
1383                             OutputType::shorthands_display(),
1384                         ),
1385                     )
1386                 });
1387                 output_types.insert(output_type, path);
1388             }
1389         }
1390     };
1391     if output_types.is_empty() {
1392         output_types.insert(OutputType::Exe, None);
1393     }
1394     OutputTypes(output_types)
1395 }
1396
1397 fn should_override_cgus_and_disable_thinlto(
1398     output_types: &OutputTypes,
1399     matches: &getopts::Matches,
1400     error_format: ErrorOutputType,
1401     mut codegen_units: Option<usize>,
1402 ) -> (bool, Option<usize>) {
1403     let mut disable_thinlto = false;
1404     // Issue #30063: if user requests LLVM-related output to one
1405     // particular path, disable codegen-units.
1406     let incompatible: Vec<_> = output_types
1407         .0
1408         .iter()
1409         .map(|ot_path| ot_path.0)
1410         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1411         .map(|ot| ot.shorthand())
1412         .collect();
1413     if !incompatible.is_empty() {
1414         match codegen_units {
1415             Some(n) if n > 1 => {
1416                 if matches.opt_present("o") {
1417                     for ot in &incompatible {
1418                         early_warn(
1419                             error_format,
1420                             &format!(
1421                                 "`--emit={}` with `-o` incompatible with \
1422                                  `-C codegen-units=N` for N > 1",
1423                                 ot
1424                             ),
1425                         );
1426                     }
1427                     early_warn(error_format, "resetting to default -C codegen-units=1");
1428                     codegen_units = Some(1);
1429                     disable_thinlto = true;
1430                 }
1431             }
1432             _ => {
1433                 codegen_units = Some(1);
1434                 disable_thinlto = true;
1435             }
1436         }
1437     }
1438
1439     if codegen_units == Some(0) {
1440         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1441     }
1442
1443     (disable_thinlto, codegen_units)
1444 }
1445
1446 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1447     if debugging_opts.threads == 0 {
1448         early_error(error_format, "value for threads must be a positive non-zero integer");
1449     }
1450
1451     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1452         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1453     }
1454 }
1455
1456 fn collect_print_requests(
1457     cg: &mut CodegenOptions,
1458     dopts: &mut DebuggingOptions,
1459     matches: &getopts::Matches,
1460     error_format: ErrorOutputType,
1461 ) -> Vec<PrintRequest> {
1462     let mut prints = Vec::<PrintRequest>::new();
1463     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1464         prints.push(PrintRequest::TargetCPUs);
1465         cg.target_cpu = None;
1466     };
1467     if cg.target_feature == "help" {
1468         prints.push(PrintRequest::TargetFeatures);
1469         cg.target_feature = String::new();
1470     }
1471
1472     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1473         "crate-name" => PrintRequest::CrateName,
1474         "file-names" => PrintRequest::FileNames,
1475         "sysroot" => PrintRequest::Sysroot,
1476         "target-libdir" => PrintRequest::TargetLibdir,
1477         "cfg" => PrintRequest::Cfg,
1478         "target-list" => PrintRequest::TargetList,
1479         "target-cpus" => PrintRequest::TargetCPUs,
1480         "target-features" => PrintRequest::TargetFeatures,
1481         "relocation-models" => PrintRequest::RelocationModels,
1482         "code-models" => PrintRequest::CodeModels,
1483         "tls-models" => PrintRequest::TlsModels,
1484         "native-static-libs" => PrintRequest::NativeStaticLibs,
1485         "target-spec-json" => {
1486             if dopts.unstable_options {
1487                 PrintRequest::TargetSpec
1488             } else {
1489                 early_error(
1490                     error_format,
1491                     "the `-Z unstable-options` flag must also be passed to \
1492                      enable the target-spec-json print option",
1493                 );
1494             }
1495         }
1496         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1497     }));
1498
1499     prints
1500 }
1501
1502 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1503     match matches.opt_str("target") {
1504         Some(target) if target.ends_with(".json") => {
1505             let path = Path::new(&target);
1506             TargetTriple::from_path(&path).unwrap_or_else(|_| {
1507                 early_error(error_format, &format!("target file {:?} does not exist", path))
1508             })
1509         }
1510         Some(target) => TargetTriple::TargetTriple(target),
1511         _ => TargetTriple::from_triple(host_triple()),
1512     }
1513 }
1514
1515 fn parse_opt_level(
1516     matches: &getopts::Matches,
1517     cg: &CodegenOptions,
1518     error_format: ErrorOutputType,
1519 ) -> OptLevel {
1520     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1521     // to use them interchangeably. However, because they're technically different flags,
1522     // we need to work out manually which should take precedence if both are supplied (i.e.
1523     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1524     // comparing them. Note that if a flag is not found, its position will be `None`, which
1525     // always compared less than `Some(_)`.
1526     let max_o = matches.opt_positions("O").into_iter().max();
1527     let max_c = matches
1528         .opt_strs_pos("C")
1529         .into_iter()
1530         .flat_map(|(i, s)| {
1531             // NB: This can match a string without `=`.
1532             if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1533         })
1534         .max();
1535     if max_o > max_c {
1536         OptLevel::Default
1537     } else {
1538         match cg.opt_level.as_ref() {
1539             "0" => OptLevel::No,
1540             "1" => OptLevel::Less,
1541             "2" => OptLevel::Default,
1542             "3" => OptLevel::Aggressive,
1543             "s" => OptLevel::Size,
1544             "z" => OptLevel::SizeMin,
1545             arg => {
1546                 early_error(
1547                     error_format,
1548                     &format!(
1549                         "optimization level needs to be \
1550                             between 0-3, s or z (instead was `{}`)",
1551                         arg
1552                     ),
1553                 );
1554             }
1555         }
1556     }
1557 }
1558
1559 fn select_debuginfo(
1560     matches: &getopts::Matches,
1561     cg: &CodegenOptions,
1562     error_format: ErrorOutputType,
1563 ) -> DebugInfo {
1564     let max_g = matches.opt_positions("g").into_iter().max();
1565     let max_c = matches
1566         .opt_strs_pos("C")
1567         .into_iter()
1568         .flat_map(|(i, s)| {
1569             // NB: This can match a string without `=`.
1570             if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1571         })
1572         .max();
1573     if max_g > max_c {
1574         DebugInfo::Full
1575     } else {
1576         match cg.debuginfo {
1577             0 => DebugInfo::None,
1578             1 => DebugInfo::Limited,
1579             2 => DebugInfo::Full,
1580             arg => {
1581                 early_error(
1582                     error_format,
1583                     &format!(
1584                         "debug info level needs to be between \
1585                          0-2 (instead was `{}`)",
1586                         arg
1587                     ),
1588                 );
1589             }
1590         }
1591     }
1592 }
1593
1594 fn parse_libs(
1595     matches: &getopts::Matches,
1596     error_format: ErrorOutputType,
1597 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1598     matches
1599         .opt_strs("l")
1600         .into_iter()
1601         .map(|s| {
1602             // Parse string of the form "[KIND=]lib[:new_name]",
1603             // where KIND is one of "dylib", "framework", "static".
1604             let (name, kind) = match s.split_once('=') {
1605                 None => (s, NativeLibKind::Unspecified),
1606                 Some((kind, name)) => {
1607                     let kind = match kind {
1608                         "dylib" => NativeLibKind::Dylib,
1609                         "framework" => NativeLibKind::Framework,
1610                         "static" => NativeLibKind::StaticBundle,
1611                         "static-nobundle" => NativeLibKind::StaticNoBundle,
1612                         s => {
1613                             early_error(
1614                                 error_format,
1615                                 &format!(
1616                                     "unknown library kind `{}`, expected \
1617                                      one of dylib, framework, or static",
1618                                     s
1619                                 ),
1620                             );
1621                         }
1622                     };
1623                     (name.to_string(), kind)
1624                 }
1625             };
1626             if kind == NativeLibKind::StaticNoBundle
1627                 && !nightly_options::match_is_nightly_build(matches)
1628             {
1629                 early_error(
1630                     error_format,
1631                     "the library kind 'static-nobundle' is only \
1632                      accepted on the nightly compiler",
1633                 );
1634             }
1635             let (name, new_name) = match name.split_once(':') {
1636                 None => (name, None),
1637                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1638             };
1639             (name, new_name, kind)
1640         })
1641         .collect()
1642 }
1643
1644 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1645     match dopts.borrowck.as_ref() {
1646         "migrate" => BorrowckMode::Migrate,
1647         "mir" => BorrowckMode::Mir,
1648         m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1649     }
1650 }
1651
1652 pub fn parse_externs(
1653     matches: &getopts::Matches,
1654     debugging_opts: &DebuggingOptions,
1655     error_format: ErrorOutputType,
1656 ) -> Externs {
1657     let is_unstable_enabled = debugging_opts.unstable_options;
1658     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1659     for arg in matches.opt_strs("extern") {
1660         let (name, path) = match arg.split_once('=') {
1661             None => (arg, None),
1662             Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1663         };
1664         let (options, name) = match name.split_once(':') {
1665             None => (None, name),
1666             Some((opts, name)) => (Some(opts), name.to_string()),
1667         };
1668
1669         let path = path.map(|p| CanonicalizedPath::new(p));
1670
1671         let entry = externs.entry(name.to_owned());
1672
1673         use std::collections::btree_map::Entry;
1674
1675         let entry = if let Some(path) = path {
1676             // --extern prelude_name=some_file.rlib
1677             match entry {
1678                 Entry::Vacant(vacant) => {
1679                     let files = BTreeSet::from_iter(iter::once(path));
1680                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1681                 }
1682                 Entry::Occupied(occupied) => {
1683                     let ext_ent = occupied.into_mut();
1684                     match ext_ent {
1685                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1686                             files.insert(path);
1687                         }
1688                         ExternEntry {
1689                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1690                             ..
1691                         } => {
1692                             // Exact paths take precedence over search directories.
1693                             let files = BTreeSet::from_iter(iter::once(path));
1694                             *location = ExternLocation::ExactPaths(files);
1695                         }
1696                     }
1697                     ext_ent
1698                 }
1699             }
1700         } else {
1701             // --extern prelude_name
1702             match entry {
1703                 Entry::Vacant(vacant) => {
1704                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1705                 }
1706                 Entry::Occupied(occupied) => {
1707                     // Ignore if already specified.
1708                     occupied.into_mut()
1709                 }
1710             }
1711         };
1712
1713         let mut is_private_dep = false;
1714         let mut add_prelude = true;
1715         if let Some(opts) = options {
1716             if !is_unstable_enabled {
1717                 early_error(
1718                     error_format,
1719                     "the `-Z unstable-options` flag must also be passed to \
1720                      enable `--extern options",
1721                 );
1722             }
1723             for opt in opts.split(',') {
1724                 match opt {
1725                     "priv" => is_private_dep = true,
1726                     "noprelude" => {
1727                         if let ExternLocation::ExactPaths(_) = &entry.location {
1728                             add_prelude = false;
1729                         } else {
1730                             early_error(
1731                                 error_format,
1732                                 "the `noprelude` --extern option requires a file path",
1733                             );
1734                         }
1735                     }
1736                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1737                 }
1738             }
1739         }
1740
1741         // Crates start out being not private, and go to being private `priv`
1742         // is specified.
1743         entry.is_private_dep |= is_private_dep;
1744         // If any flag is missing `noprelude`, then add to the prelude.
1745         entry.add_prelude |= add_prelude;
1746     }
1747     Externs(externs)
1748 }
1749
1750 fn parse_extern_dep_specs(
1751     matches: &getopts::Matches,
1752     debugging_opts: &DebuggingOptions,
1753     error_format: ErrorOutputType,
1754 ) -> ExternDepSpecs {
1755     let is_unstable_enabled = debugging_opts.unstable_options;
1756     let mut map = BTreeMap::new();
1757
1758     for arg in matches.opt_strs("extern-location") {
1759         if !is_unstable_enabled {
1760             early_error(
1761                 error_format,
1762                 "`--extern-location` option is unstable: set `-Z unstable-options`",
1763             );
1764         }
1765
1766         let mut parts = arg.splitn(2, '=');
1767         let name = parts.next().unwrap_or_else(|| {
1768             early_error(error_format, "`--extern-location` value must not be empty")
1769         });
1770         let loc = parts.next().unwrap_or_else(|| {
1771             early_error(
1772                 error_format,
1773                 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1774             )
1775         });
1776
1777         let locparts: Vec<_> = loc.split(":").collect();
1778         let spec = match &locparts[..] {
1779             ["raw", ..] => {
1780                 // Don't want `:` split string
1781                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1782                     early_error(error_format, "`--extern-location`: missing `raw` location")
1783                 });
1784                 ExternDepSpec::Raw(raw.to_string())
1785             }
1786             ["json", ..] => {
1787                 // Don't want `:` split string
1788                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1789                     early_error(error_format, "`--extern-location`: missing `json` location")
1790                 });
1791                 let json = json::from_str(raw).unwrap_or_else(|_| {
1792                     early_error(
1793                         error_format,
1794                         &format!("`--extern-location`: malformed json location `{}`", raw),
1795                     )
1796                 });
1797                 ExternDepSpec::Json(json)
1798             }
1799             [bad, ..] => early_error(
1800                 error_format,
1801                 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1802             ),
1803             [] => early_error(error_format, "missing location specification"),
1804         };
1805
1806         map.insert(name.to_string(), spec);
1807     }
1808
1809     ExternDepSpecs::new(map)
1810 }
1811
1812 fn parse_remap_path_prefix(
1813     matches: &getopts::Matches,
1814     error_format: ErrorOutputType,
1815 ) -> Vec<(PathBuf, PathBuf)> {
1816     matches
1817         .opt_strs("remap-path-prefix")
1818         .into_iter()
1819         .map(|remap| match remap.rsplit_once('=') {
1820             None => early_error(
1821                 error_format,
1822                 "--remap-path-prefix must contain '=' between FROM and TO",
1823             ),
1824             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1825         })
1826         .collect()
1827 }
1828
1829 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1830     let color = parse_color(matches);
1831
1832     let edition = parse_crate_edition(matches);
1833
1834     let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1835         parse_json(matches);
1836
1837     let error_format = parse_error_format(matches, color, json_rendered);
1838
1839     let unparsed_crate_types = matches.opt_strs("crate-type");
1840     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1841         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1842
1843     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1844
1845     let mut debugging_opts = build_debugging_options(matches, error_format);
1846     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1847
1848     if !debugging_opts.unstable_options && json_unused_externs {
1849         early_error(
1850             error_format,
1851             "the `-Z unstable-options` flag must also be passed to enable \
1852             the flag `--json=unused-externs`",
1853         );
1854     }
1855
1856     let output_types = parse_output_types(&debugging_opts, matches, error_format);
1857
1858     let mut cg = build_codegen_options(matches, error_format);
1859     let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1860         &output_types,
1861         matches,
1862         error_format,
1863         cg.codegen_units,
1864     );
1865
1866     check_thread_count(&debugging_opts, error_format);
1867
1868     let incremental = cg.incremental.as_ref().map(PathBuf::from);
1869
1870     if debugging_opts.profile && incremental.is_some() {
1871         early_error(
1872             error_format,
1873             "can't instrument with gcov profiling when compiling incrementally",
1874         );
1875     }
1876     if debugging_opts.profile {
1877         match codegen_units {
1878             Some(1) => {}
1879             None => codegen_units = Some(1),
1880             Some(_) => early_error(
1881                 error_format,
1882                 "can't instrument with gcov profiling with multiple codegen units",
1883             ),
1884         }
1885     }
1886
1887     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1888         early_error(
1889             error_format,
1890             "options `-C profile-generate` and `-C profile-use` are exclusive",
1891         );
1892     }
1893
1894     if debugging_opts.instrument_coverage.is_some()
1895         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1896     {
1897         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1898             early_error(
1899                 error_format,
1900                 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1901                 or `-C profile-generate`",
1902             );
1903         }
1904
1905         // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1906         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1907         // multiple runs, including some changes to source code; so mangled names must be consistent
1908         // across compilations.
1909         match debugging_opts.symbol_mangling_version {
1910             None => {
1911                 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1912             }
1913             Some(SymbolManglingVersion::Legacy) => {
1914                 early_warn(
1915                     error_format,
1916                     "-Z instrument-coverage requires symbol mangling version `v0`, \
1917                     but `-Z symbol-mangling-version=legacy` was specified",
1918                 );
1919             }
1920             Some(SymbolManglingVersion::V0) => {}
1921         }
1922     }
1923
1924     if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1925         debugging_opts.graphviz_font = graphviz_font;
1926     }
1927
1928     if !cg.embed_bitcode {
1929         match cg.lto {
1930             LtoCli::No | LtoCli::Unspecified => {}
1931             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1932                 error_format,
1933                 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1934             ),
1935         }
1936     }
1937
1938     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1939
1940     let cg = cg;
1941
1942     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1943     let target_triple = parse_target_triple(matches, error_format);
1944     let opt_level = parse_opt_level(matches, &cg, error_format);
1945     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1946     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1947     // for more details.
1948     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1949     let debuginfo = select_debuginfo(matches, &cg, error_format);
1950
1951     let mut search_paths = vec![];
1952     for s in &matches.opt_strs("L") {
1953         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1954     }
1955
1956     let libs = parse_libs(matches, error_format);
1957
1958     let test = matches.opt_present("test");
1959
1960     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1961
1962     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1963         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1964     }
1965
1966     let externs = parse_externs(matches, &debugging_opts, error_format);
1967     let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
1968
1969     let crate_name = matches.opt_str("crate-name");
1970
1971     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1972
1973     let pretty = parse_pretty(matches, &debugging_opts, error_format);
1974
1975     if !debugging_opts.unstable_options
1976         && !target_triple.triple().contains("apple")
1977         && cg.split_debuginfo.is_some()
1978     {
1979         {
1980             early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
1981         }
1982     }
1983
1984     // Try to find a directory containing the Rust `src`, for more details see
1985     // the doc comment on the `real_rust_source_base_dir` field.
1986     let tmp_buf;
1987     let sysroot = match &sysroot_opt {
1988         Some(s) => s,
1989         None => {
1990             tmp_buf = crate::filesearch::get_or_default_sysroot();
1991             &tmp_buf
1992         }
1993     };
1994     let real_rust_source_base_dir = {
1995         // This is the location used by the `rust-src` `rustup` component.
1996         let mut candidate = sysroot.join("lib/rustlib/src/rust");
1997         if let Ok(metadata) = candidate.symlink_metadata() {
1998             // Replace the symlink rustbuild creates, with its destination.
1999             // We could try to use `fs::canonicalize` instead, but that might
2000             // produce unnecessarily verbose path.
2001             if metadata.file_type().is_symlink() {
2002                 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2003                     candidate = symlink_dest;
2004                 }
2005             }
2006         }
2007
2008         // Only use this directory if it has a file we can expect to always find.
2009         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2010     };
2011
2012     Options {
2013         crate_types,
2014         optimize: opt_level,
2015         debuginfo,
2016         lint_opts,
2017         lint_cap,
2018         describe_lints,
2019         output_types,
2020         search_paths,
2021         maybe_sysroot: sysroot_opt,
2022         target_triple,
2023         test,
2024         incremental,
2025         debugging_opts,
2026         prints,
2027         borrowck_mode,
2028         cg,
2029         error_format,
2030         externs,
2031         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2032         extern_dep_specs,
2033         crate_name,
2034         alt_std_name: None,
2035         libs,
2036         debug_assertions,
2037         actually_rustdoc: false,
2038         trimmed_def_paths: TrimmedDefPaths::default(),
2039         cli_forced_codegen_units: codegen_units,
2040         cli_forced_thinlto_off: disable_thinlto,
2041         remap_path_prefix,
2042         real_rust_source_base_dir,
2043         edition,
2044         json_artifact_notifications,
2045         json_unused_externs,
2046         pretty,
2047     }
2048 }
2049
2050 fn parse_pretty(
2051     matches: &getopts::Matches,
2052     debugging_opts: &DebuggingOptions,
2053     efmt: ErrorOutputType,
2054 ) -> Option<PpMode> {
2055     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2056         use PpMode::*;
2057         let first = match (name, extended) {
2058             ("normal", _) => Source(PpSourceMode::Normal),
2059             ("identified", _) => Source(PpSourceMode::Identified),
2060             ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2061             ("expanded", _) => Source(PpSourceMode::Expanded),
2062             ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2063             ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2064             ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2065             ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2066             ("hir", true) => Hir(PpHirMode::Normal),
2067             ("hir,identified", true) => Hir(PpHirMode::Identified),
2068             ("hir,typed", true) => Hir(PpHirMode::Typed),
2069             ("hir-tree", true) => HirTree,
2070             ("thir-tree", true) => ThirTree,
2071             ("mir", true) => Mir,
2072             ("mir-cfg", true) => MirCFG,
2073             _ => {
2074                 if extended {
2075                     early_error(
2076                         efmt,
2077                         &format!(
2078                             "argument to `unpretty` must be one of `normal`, \
2079                                         `expanded`, `identified`, `expanded,identified`, \
2080                                         `expanded,hygiene`, `everybody_loops`, \
2081                                         `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2082                                         `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2083                             name
2084                         ),
2085                     );
2086                 } else {
2087                     early_error(
2088                         efmt,
2089                         &format!(
2090                             "argument to `pretty` must be one of `normal`, \
2091                                         `expanded`, `identified`, or `expanded,identified`; got {}",
2092                             name
2093                         ),
2094                     );
2095                 }
2096             }
2097         };
2098         tracing::debug!("got unpretty option: {:?}", first);
2099         first
2100     }
2101
2102     if debugging_opts.unstable_options {
2103         if let Some(a) = matches.opt_default("pretty", "normal") {
2104             // stable pretty-print variants only
2105             return Some(parse_pretty_inner(efmt, &a, false));
2106         }
2107     }
2108
2109     debugging_opts.unpretty.as_ref().map(|a| {
2110         // extended with unstable pretty-print variants
2111         parse_pretty_inner(efmt, &a, true)
2112     })
2113 }
2114
2115 pub fn make_crate_type_option() -> RustcOptGroup {
2116     opt::multi_s(
2117         "",
2118         "crate-type",
2119         "Comma separated list of types of crates
2120                                 for the compiler to emit",
2121         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2122     )
2123 }
2124
2125 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2126     let mut crate_types: Vec<CrateType> = Vec::new();
2127     for unparsed_crate_type in &list_list {
2128         for part in unparsed_crate_type.split(',') {
2129             let new_part = match part {
2130                 "lib" => default_lib_output(),
2131                 "rlib" => CrateType::Rlib,
2132                 "staticlib" => CrateType::Staticlib,
2133                 "dylib" => CrateType::Dylib,
2134                 "cdylib" => CrateType::Cdylib,
2135                 "bin" => CrateType::Executable,
2136                 "proc-macro" => CrateType::ProcMacro,
2137                 _ => return Err(format!("unknown crate type: `{}`", part)),
2138             };
2139             if !crate_types.contains(&new_part) {
2140                 crate_types.push(new_part)
2141             }
2142         }
2143     }
2144
2145     Ok(crate_types)
2146 }
2147
2148 pub mod nightly_options {
2149     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2150     use crate::early_error;
2151     use rustc_feature::UnstableFeatures;
2152
2153     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2154         match_is_nightly_build(matches)
2155             && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2156     }
2157
2158     pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2159         is_nightly_build(matches.opt_str("crate-name").as_deref())
2160     }
2161
2162     pub fn is_nightly_build(krate: Option<&str>) -> bool {
2163         UnstableFeatures::from_environment(krate).is_nightly_build()
2164     }
2165
2166     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2167         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2168         let really_allows_unstable_options = match_is_nightly_build(matches);
2169
2170         for opt in flags.iter() {
2171             if opt.stability == OptionStability::Stable {
2172                 continue;
2173             }
2174             if !matches.opt_present(opt.name) {
2175                 continue;
2176             }
2177             if opt.name != "Z" && !has_z_unstable_option {
2178                 early_error(
2179                     ErrorOutputType::default(),
2180                     &format!(
2181                         "the `-Z unstable-options` flag must also be passed to enable \
2182                          the flag `{}`",
2183                         opt.name
2184                     ),
2185                 );
2186             }
2187             if really_allows_unstable_options {
2188                 continue;
2189             }
2190             match opt.stability {
2191                 OptionStability::Unstable => {
2192                     let msg = format!(
2193                         "the option `{}` is only accepted on the \
2194                          nightly compiler",
2195                         opt.name
2196                     );
2197                     early_error(ErrorOutputType::default(), &msg);
2198                 }
2199                 OptionStability::Stable => {}
2200             }
2201         }
2202     }
2203 }
2204
2205 impl fmt::Display for CrateType {
2206     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2207         match *self {
2208             CrateType::Executable => "bin".fmt(f),
2209             CrateType::Dylib => "dylib".fmt(f),
2210             CrateType::Rlib => "rlib".fmt(f),
2211             CrateType::Staticlib => "staticlib".fmt(f),
2212             CrateType::Cdylib => "cdylib".fmt(f),
2213             CrateType::ProcMacro => "proc-macro".fmt(f),
2214         }
2215     }
2216 }
2217
2218 #[derive(Copy, Clone, PartialEq, Debug)]
2219 pub enum PpSourceMode {
2220     /// `--pretty=normal`
2221     Normal,
2222     /// `-Zunpretty=everybody_loops`
2223     EveryBodyLoops,
2224     /// `--pretty=expanded`
2225     Expanded,
2226     /// `--pretty=identified`
2227     Identified,
2228     /// `--pretty=expanded,identified`
2229     ExpandedIdentified,
2230     /// `--pretty=expanded,hygiene`
2231     ExpandedHygiene,
2232 }
2233
2234 #[derive(Copy, Clone, PartialEq, Debug)]
2235 pub enum PpAstTreeMode {
2236     /// `-Zunpretty=ast`
2237     Normal,
2238     /// `-Zunpretty=ast,expanded`
2239     Expanded,
2240 }
2241
2242 #[derive(Copy, Clone, PartialEq, Debug)]
2243 pub enum PpHirMode {
2244     /// `-Zunpretty=hir`
2245     Normal,
2246     /// `-Zunpretty=hir,identified`
2247     Identified,
2248     /// `-Zunpretty=hir,typed`
2249     Typed,
2250 }
2251
2252 #[derive(Copy, Clone, PartialEq, Debug)]
2253 pub enum PpMode {
2254     /// Options that print the source code, i.e.
2255     /// `--pretty` and `-Zunpretty=everybody_loops`
2256     Source(PpSourceMode),
2257     AstTree(PpAstTreeMode),
2258     /// Options that print the HIR, i.e. `-Zunpretty=hir`
2259     Hir(PpHirMode),
2260     /// `-Zunpretty=hir-tree`
2261     HirTree,
2262     /// `-Zunpretty=thir-tree`
2263     ThirTree,
2264     /// `-Zunpretty=mir`
2265     Mir,
2266     /// `-Zunpretty=mir-cfg`
2267     MirCFG,
2268 }
2269
2270 impl PpMode {
2271     pub fn needs_ast_map(&self) -> bool {
2272         use PpMode::*;
2273         use PpSourceMode::*;
2274         match *self {
2275             Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2276
2277             Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2278             | AstTree(PpAstTreeMode::Expanded)
2279             | Hir(_)
2280             | HirTree
2281             | ThirTree
2282             | Mir
2283             | MirCFG => true,
2284         }
2285     }
2286
2287     pub fn needs_analysis(&self) -> bool {
2288         use PpMode::*;
2289         matches!(*self, Mir | MirCFG | ThirTree)
2290     }
2291 }
2292
2293 /// Command-line arguments passed to the compiler have to be incorporated with
2294 /// the dependency tracking system for incremental compilation. This module
2295 /// provides some utilities to make this more convenient.
2296 ///
2297 /// The values of all command-line arguments that are relevant for dependency
2298 /// tracking are hashed into a single value that determines whether the
2299 /// incremental compilation cache can be re-used or not. This hashing is done
2300 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2301 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2302 /// the hash of which is order dependent, but we might not want the order of
2303 /// arguments to make a difference for the hash).
2304 ///
2305 /// However, since the value provided by `Hash::hash` often *is* suitable,
2306 /// especially for primitive types, there is the
2307 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2308 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2309 /// we have an opt-in scheme here, so one is hopefully forced to think about
2310 /// how the hash should be calculated when adding a new command-line argument.
2311 crate mod dep_tracking {
2312     use super::{
2313         CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2314         LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2315         SymbolManglingVersion, TrimmedDefPaths,
2316     };
2317     use crate::lint;
2318     use crate::options::WasiExecModel;
2319     use crate::utils::NativeLibKind;
2320     use rustc_feature::UnstableFeatures;
2321     use rustc_span::edition::Edition;
2322     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2323     use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2324     use std::collections::hash_map::DefaultHasher;
2325     use std::collections::BTreeMap;
2326     use std::hash::Hash;
2327     use std::num::NonZeroUsize;
2328     use std::path::PathBuf;
2329
2330     pub trait DepTrackingHash {
2331         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2332     }
2333
2334     macro_rules! impl_dep_tracking_hash_via_hash {
2335         ($($t:ty),+ $(,)?) => {$(
2336             impl DepTrackingHash for $t {
2337                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2338                     Hash::hash(self, hasher);
2339                 }
2340             }
2341         )+};
2342     }
2343
2344     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2345         ($($t:ty),+ $(,)?) => {$(
2346             impl DepTrackingHash for Vec<$t> {
2347                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2348                     let mut elems: Vec<&$t> = self.iter().collect();
2349                     elems.sort();
2350                     Hash::hash(&elems.len(), hasher);
2351                     for (index, elem) in elems.iter().enumerate() {
2352                         Hash::hash(&index, hasher);
2353                         DepTrackingHash::hash(*elem, hasher, error_format);
2354                     }
2355                 }
2356             }
2357         )+};
2358     }
2359
2360     impl_dep_tracking_hash_via_hash!(
2361         bool,
2362         usize,
2363         u64,
2364         String,
2365         PathBuf,
2366         lint::Level,
2367         Option<bool>,
2368         Option<u32>,
2369         Option<usize>,
2370         Option<NonZeroUsize>,
2371         Option<String>,
2372         Option<(String, u64)>,
2373         Option<Vec<String>>,
2374         Option<MergeFunctions>,
2375         Option<RelocModel>,
2376         Option<CodeModel>,
2377         Option<TlsModel>,
2378         Option<WasiExecModel>,
2379         Option<PanicStrategy>,
2380         Option<RelroLevel>,
2381         Option<InstrumentCoverage>,
2382         Option<lint::Level>,
2383         Option<PathBuf>,
2384         CrateType,
2385         MergeFunctions,
2386         PanicStrategy,
2387         RelroLevel,
2388         Passes,
2389         OptLevel,
2390         LtoCli,
2391         DebugInfo,
2392         UnstableFeatures,
2393         OutputTypes,
2394         NativeLibKind,
2395         SanitizerSet,
2396         CFGuard,
2397         TargetTriple,
2398         Edition,
2399         LinkerPluginLto,
2400         Option<SplitDebuginfo>,
2401         SwitchWithOptPath,
2402         Option<SymbolManglingVersion>,
2403         Option<SourceFileHashAlgorithm>,
2404         TrimmedDefPaths,
2405     );
2406
2407     impl_dep_tracking_hash_for_sortable_vec_of!(
2408         String,
2409         PathBuf,
2410         (PathBuf, PathBuf),
2411         CrateType,
2412         (String, lint::Level),
2413         (String, Option<String>, NativeLibKind),
2414         (String, u64)
2415     );
2416
2417     impl<T1, T2> DepTrackingHash for (T1, T2)
2418     where
2419         T1: DepTrackingHash,
2420         T2: DepTrackingHash,
2421     {
2422         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2423             Hash::hash(&0, hasher);
2424             DepTrackingHash::hash(&self.0, hasher, error_format);
2425             Hash::hash(&1, hasher);
2426             DepTrackingHash::hash(&self.1, hasher, error_format);
2427         }
2428     }
2429
2430     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2431     where
2432         T1: DepTrackingHash,
2433         T2: DepTrackingHash,
2434         T3: DepTrackingHash,
2435     {
2436         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2437             Hash::hash(&0, hasher);
2438             DepTrackingHash::hash(&self.0, hasher, error_format);
2439             Hash::hash(&1, hasher);
2440             DepTrackingHash::hash(&self.1, hasher, error_format);
2441             Hash::hash(&2, hasher);
2442             DepTrackingHash::hash(&self.2, hasher, error_format);
2443         }
2444     }
2445
2446     // This is a stable hash because BTreeMap is a sorted container
2447     crate fn stable_hash(
2448         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2449         hasher: &mut DefaultHasher,
2450         error_format: ErrorOutputType,
2451     ) {
2452         for (key, sub_hash) in sub_hashes {
2453             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2454             // the keys, as they are just plain strings
2455             Hash::hash(&key.len(), hasher);
2456             Hash::hash(key, hasher);
2457             sub_hash.hash(hasher, error_format);
2458         }
2459     }
2460 }