]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_session/src/config.rs
Rollup merge of #87307 - michaelwoerister:pgo-unwind-msvc, r=nagisa
[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, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
10
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
16
17 use rustc_serialize::json;
18
19 use crate::parse::CrateConfig;
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::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::hash::Hash;
35 use std::iter::{self, FromIterator};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
38
39 /// The different settings that the `-Z strip` flag can have.
40 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
41 pub enum Strip {
42     /// Do not strip at all.
43     None,
44
45     /// Strip debuginfo.
46     Debuginfo,
47
48     /// Strip all symbols.
49     Symbols,
50 }
51
52 /// The different settings that the `-C control-flow-guard` flag can have.
53 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
54 pub enum CFGuard {
55     /// Do not emit Control Flow Guard metadata or checks.
56     Disabled,
57
58     /// Emit Control Flow Guard metadata but no checks.
59     NoChecks,
60
61     /// Emit Control Flow Guard metadata and checks.
62     Checks,
63 }
64
65 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
66 pub enum OptLevel {
67     No,         // -O0
68     Less,       // -O1
69     Default,    // -O2
70     Aggressive, // -O3
71     Size,       // -Os
72     SizeMin,    // -Oz
73 }
74
75 impl_stable_hash_via_hash!(OptLevel);
76
77 /// This is what the `LtoCli` values get mapped to after resolving defaults and
78 /// and taking other command line options into account.
79 ///
80 /// Note that linker plugin-based LTO is a different mechanism entirely.
81 #[derive(Clone, PartialEq)]
82 pub enum Lto {
83     /// Don't do any LTO whatsoever.
84     No,
85
86     /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
87     Thin,
88
89     /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
90     /// only relevant if multiple CGUs are used.
91     ThinLocal,
92
93     /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
94     Fat,
95 }
96
97 /// The different settings that the `-C lto` flag can have.
98 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
99 pub enum LtoCli {
100     /// `-C lto=no`
101     No,
102     /// `-C lto=yes`
103     Yes,
104     /// `-C lto`
105     NoParam,
106     /// `-C lto=thin`
107     Thin,
108     /// `-C lto=fat`
109     Fat,
110     /// No `-C lto` flag passed
111     Unspecified,
112 }
113
114 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
115 /// document highlighting each span of every statement (including terminators). `Terminator` and
116 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
117 /// computed span for the block, representing the entire range, covering the block's terminator and
118 /// all of its statements.
119 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
120 pub enum MirSpanview {
121     /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
122     Statement,
123     /// `-Z dump_mir_spanview=terminator`
124     Terminator,
125     /// `-Z dump_mir_spanview=block`
126     Block,
127 }
128
129 /// The different settings that the `-Z instrument-coverage` flag can have.
130 ///
131 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
132 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
133 /// and higher). Nevertheless, there are many variables, depending on options
134 /// selected, code structure, and enabled attributes. If errors are encountered,
135 /// either while compiling or when generating `llvm-cov show` reports, consider
136 /// lowering the optimization level, including or excluding `-C link-dead-code`,
137 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
138 /// instrument-coverage=except-unused-generics`.
139 ///
140 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
141 /// coverage map, it will not attempt to generate synthetic functions for unused
142 /// (and not code-generated) functions (whether they are generic or not). As a
143 /// result, non-codegenned functions will not be included in the coverage map,
144 /// and will not appear, as covered or uncovered, in coverage reports.
145 ///
146 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
147 /// unless the function has type parameters.
148 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
149 pub enum InstrumentCoverage {
150     /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
151     All,
152     /// `-Z instrument-coverage=except-unused-generics`
153     ExceptUnusedGenerics,
154     /// `-Z instrument-coverage=except-unused-functions`
155     ExceptUnusedFunctions,
156     /// `-Z instrument-coverage=off` (or `no`, etc.)
157     Off,
158 }
159
160 #[derive(Clone, PartialEq, Hash, Debug)]
161 pub enum LinkerPluginLto {
162     LinkerPlugin(PathBuf),
163     LinkerPluginAuto,
164     Disabled,
165 }
166
167 impl LinkerPluginLto {
168     pub fn enabled(&self) -> bool {
169         match *self {
170             LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
171             LinkerPluginLto::Disabled => false,
172         }
173     }
174 }
175
176 #[derive(Clone, PartialEq, Hash, Debug)]
177 pub enum SwitchWithOptPath {
178     Enabled(Option<PathBuf>),
179     Disabled,
180 }
181
182 impl SwitchWithOptPath {
183     pub fn enabled(&self) -> bool {
184         match *self {
185             SwitchWithOptPath::Enabled(_) => true,
186             SwitchWithOptPath::Disabled => false,
187         }
188     }
189 }
190
191 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
192 #[derive(Encodable, Decodable)]
193 pub enum SymbolManglingVersion {
194     Legacy,
195     V0,
196 }
197
198 impl_stable_hash_via_hash!(SymbolManglingVersion);
199
200 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
201 pub enum DebugInfo {
202     None,
203     Limited,
204     Full,
205 }
206
207 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
208 #[derive(Encodable, Decodable)]
209 pub enum OutputType {
210     Bitcode,
211     Assembly,
212     LlvmAssembly,
213     Mir,
214     Metadata,
215     Object,
216     Exe,
217     DepInfo,
218 }
219
220 impl_stable_hash_via_hash!(OutputType);
221
222 impl OutputType {
223     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
224         match *self {
225             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
226             OutputType::Bitcode
227             | OutputType::Assembly
228             | OutputType::LlvmAssembly
229             | OutputType::Mir
230             | OutputType::Object => false,
231         }
232     }
233
234     fn shorthand(&self) -> &'static str {
235         match *self {
236             OutputType::Bitcode => "llvm-bc",
237             OutputType::Assembly => "asm",
238             OutputType::LlvmAssembly => "llvm-ir",
239             OutputType::Mir => "mir",
240             OutputType::Object => "obj",
241             OutputType::Metadata => "metadata",
242             OutputType::Exe => "link",
243             OutputType::DepInfo => "dep-info",
244         }
245     }
246
247     fn from_shorthand(shorthand: &str) -> Option<Self> {
248         Some(match shorthand {
249             "asm" => OutputType::Assembly,
250             "llvm-ir" => OutputType::LlvmAssembly,
251             "mir" => OutputType::Mir,
252             "llvm-bc" => OutputType::Bitcode,
253             "obj" => OutputType::Object,
254             "metadata" => OutputType::Metadata,
255             "link" => OutputType::Exe,
256             "dep-info" => OutputType::DepInfo,
257             _ => return None,
258         })
259     }
260
261     fn shorthands_display() -> String {
262         format!(
263             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
264             OutputType::Bitcode.shorthand(),
265             OutputType::Assembly.shorthand(),
266             OutputType::LlvmAssembly.shorthand(),
267             OutputType::Mir.shorthand(),
268             OutputType::Object.shorthand(),
269             OutputType::Metadata.shorthand(),
270             OutputType::Exe.shorthand(),
271             OutputType::DepInfo.shorthand(),
272         )
273     }
274
275     pub fn extension(&self) -> &'static str {
276         match *self {
277             OutputType::Bitcode => "bc",
278             OutputType::Assembly => "s",
279             OutputType::LlvmAssembly => "ll",
280             OutputType::Mir => "mir",
281             OutputType::Object => "o",
282             OutputType::Metadata => "rmeta",
283             OutputType::DepInfo => "d",
284             OutputType::Exe => "",
285         }
286     }
287 }
288
289 /// The type of diagnostics output to generate.
290 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
291 pub enum ErrorOutputType {
292     /// Output meant for the consumption of humans.
293     HumanReadable(HumanReadableErrorType),
294     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
295     Json {
296         /// Render the JSON in a human readable way (with indents and newlines).
297         pretty: bool,
298         /// The JSON output includes a `rendered` field that includes the rendered
299         /// human output.
300         json_rendered: HumanReadableErrorType,
301     },
302 }
303
304 impl Default for ErrorOutputType {
305     fn default() -> Self {
306         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
307     }
308 }
309
310 /// Parameter to control path trimming.
311 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
312 pub enum TrimmedDefPaths {
313     /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
314     Never,
315     /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
316     Always,
317     /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
318     GoodPath,
319 }
320
321 impl Default for TrimmedDefPaths {
322     fn default() -> Self {
323         Self::Never
324     }
325 }
326
327 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
328 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
329 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
330 /// should only depend on the output types, not the paths they're written to.
331 #[derive(Clone, Debug, Hash)]
332 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
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: Default::default(),
689             prints: Vec::new(),
690             borrowck_mode: BorrowckMode::Migrate,
691             cg: Default::default(),
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 abi = &sess.target.abi;
808     let vendor = &sess.target.vendor;
809     let min_atomic_width = sess.target.min_atomic_width();
810     let max_atomic_width = sess.target.max_atomic_width();
811     let atomic_cas = sess.target.atomic_cas;
812     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
813         sess.fatal(&err);
814     });
815
816     let mut ret = FxHashSet::default();
817     ret.reserve(7); // the minimum number of insertions
818     // Target bindings.
819     ret.insert((sym::target_os, Some(Symbol::intern(os))));
820     for fam in &sess.target.families {
821         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
822         if fam == "windows" {
823             ret.insert((sym::windows, None));
824         } else if fam == "unix" {
825             ret.insert((sym::unix, None));
826         }
827     }
828     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
829     ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
830     ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
831     ret.insert((sym::target_env, Some(Symbol::intern(env))));
832     ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
833     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
834     if sess.target.has_elf_tls {
835         ret.insert((sym::target_thread_local, None));
836     }
837     for (i, align) in [
838         (8, layout.i8_align.abi),
839         (16, layout.i16_align.abi),
840         (32, layout.i32_align.abi),
841         (64, layout.i64_align.abi),
842         (128, layout.i128_align.abi),
843     ] {
844         if i >= min_atomic_width && i <= max_atomic_width {
845             let mut insert_atomic = |s, align: Align| {
846                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
847                 if atomic_cas {
848                     ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
849                 }
850                 if align.bits() == i {
851                     ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
852                 }
853             };
854             let s = i.to_string();
855             insert_atomic(&s, align);
856             if s == wordsz {
857                 insert_atomic("ptr", layout.pointer_align.abi);
858             }
859         }
860     }
861
862     let panic_strategy = sess.panic_strategy();
863     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
864
865     for s in sess.opts.debugging_opts.sanitizer {
866         let symbol = Symbol::intern(&s.to_string());
867         ret.insert((sym::sanitize, Some(symbol)));
868     }
869
870     if sess.opts.debug_assertions {
871         ret.insert((sym::debug_assertions, None));
872     }
873     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
874         ret.insert((sym::proc_macro, None));
875     }
876     ret
877 }
878
879 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
880 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
881 /// but the symbol interner is not yet set up then, so we must convert it later.
882 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
883     cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
884 }
885
886 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
887     // Combine the configuration requested by the session (command line) with
888     // some default and generated configuration items.
889     let default_cfg = default_configuration(sess);
890     // If the user wants a test runner, then add the test cfg.
891     if sess.opts.test {
892         user_cfg.insert((sym::test, None));
893     }
894     user_cfg.extend(default_cfg.iter().cloned());
895     user_cfg
896 }
897
898 pub(super) fn build_target_config(
899     opts: &Options,
900     target_override: Option<Target>,
901     sysroot: &PathBuf,
902 ) -> Target {
903     let target_result = target_override.map_or_else(
904         || Target::search(&opts.target_triple, sysroot),
905         |t| Ok((t, TargetWarnings::empty())),
906     );
907     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
908         early_error(
909             opts.error_format,
910             &format!(
911                 "Error loading target specification: {}. \
912                  Run `rustc --print target-list` for a list of built-in targets",
913                 e
914             ),
915         )
916     });
917     for warning in target_warnings.warning_messages() {
918         early_warn(opts.error_format, &warning)
919     }
920
921     if !matches!(target.pointer_width, 16 | 32 | 64) {
922         early_error(
923             opts.error_format,
924             &format!(
925                 "target specification was invalid: \
926              unrecognized target-pointer-width {}",
927                 target.pointer_width
928             ),
929         )
930     }
931
932     target
933 }
934
935 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
936 pub enum OptionStability {
937     Stable,
938     Unstable,
939 }
940
941 pub struct RustcOptGroup {
942     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
943     pub name: &'static str,
944     pub stability: OptionStability,
945 }
946
947 impl RustcOptGroup {
948     pub fn is_stable(&self) -> bool {
949         self.stability == OptionStability::Stable
950     }
951
952     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
953     where
954         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
955     {
956         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
957     }
958
959     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
960     where
961         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
962     {
963         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
964     }
965 }
966
967 // The `opt` local module holds wrappers around the `getopts` API that
968 // adds extra rustc-specific metadata to each option; such metadata
969 // is exposed by .  The public
970 // functions below ending with `_u` are the functions that return
971 // *unstable* options, i.e., options that are only enabled when the
972 // user also passes the `-Z unstable-options` debugging flag.
973 mod opt {
974     // The `fn flag*` etc below are written so that we can use them
975     // in the future; do not warn about them not being used right now.
976     #![allow(dead_code)]
977
978     use super::RustcOptGroup;
979
980     pub type R = RustcOptGroup;
981     pub type S = &'static str;
982
983     fn stable<F>(name: S, f: F) -> R
984     where
985         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
986     {
987         RustcOptGroup::stable(name, f)
988     }
989
990     fn unstable<F>(name: S, f: F) -> R
991     where
992         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
993     {
994         RustcOptGroup::unstable(name, f)
995     }
996
997     fn longer(a: S, b: S) -> S {
998         if a.len() > b.len() { a } else { b }
999     }
1000
1001     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1002         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1003     }
1004     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1005         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1006     }
1007     pub fn flag_s(a: S, b: S, c: S) -> R {
1008         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1009     }
1010     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1011         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1012     }
1013
1014     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1015         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1016     }
1017     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1018         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1019     }
1020 }
1021
1022 /// Returns the "short" subset of the rustc command line options,
1023 /// including metadata for each option, such as whether the option is
1024 /// part of the stable long-term interface for rustc.
1025 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1026     vec![
1027         opt::flag_s("h", "help", "Display this message"),
1028         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1029         opt::multi_s(
1030             "L",
1031             "",
1032             "Add a directory to the library search path. The
1033                              optional KIND can be one of dependency, crate, native,
1034                              framework, or all (the default).",
1035             "[KIND=]PATH",
1036         ),
1037         opt::multi_s(
1038             "l",
1039             "",
1040             "Link the generated crate(s) to the specified native
1041                              library NAME. The optional KIND can be one of
1042                              static, framework, or dylib (the default).
1043                              Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1044                              may be specified each with a prefix of either '+' to
1045                              enable or '-' to disable.",
1046             "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1047         ),
1048         make_crate_type_option(),
1049         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1050         opt::opt_s(
1051             "",
1052             "edition",
1053             "Specify which edition of the compiler to use when compiling code.",
1054             EDITION_NAME_LIST,
1055         ),
1056         opt::multi_s(
1057             "",
1058             "emit",
1059             "Comma separated list of types of output for \
1060              the compiler to emit",
1061             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1062         ),
1063         opt::multi_s(
1064             "",
1065             "print",
1066             "Compiler information to print on stdout",
1067             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1068              target-cpus|target-features|relocation-models|\
1069              code-models|tls-models|target-spec-json|native-static-libs]",
1070         ),
1071         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1072         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1073         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1074         opt::opt_s(
1075             "",
1076             "out-dir",
1077             "Write output to compiler-chosen filename \
1078              in <dir>",
1079             "DIR",
1080         ),
1081         opt::opt_s(
1082             "",
1083             "explain",
1084             "Provide a detailed explanation of an error \
1085              message",
1086             "OPT",
1087         ),
1088         opt::flag_s("", "test", "Build a test harness"),
1089         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1090         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1091         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1092         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1093         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1094         opt::multi_s(
1095             "",
1096             "cap-lints",
1097             "Set the most restrictive lint level. \
1098              More restrictive lints are capped at this \
1099              level",
1100             "LEVEL",
1101         ),
1102         opt::multi_s(
1103             "",
1104             "force-warn",
1105             "Specifiy lints that should warn even if \
1106              they are allowed somewhere else",
1107             "LINT",
1108         ),
1109         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1110         opt::flag_s("V", "version", "Print version info and exit"),
1111         opt::flag_s("v", "verbose", "Use verbose output"),
1112     ]
1113 }
1114
1115 /// Returns all rustc command line options, including metadata for
1116 /// each option, such as whether the option is part of the stable
1117 /// long-term interface for rustc.
1118 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1119     let mut opts = rustc_short_optgroups();
1120     opts.extend(vec![
1121         opt::multi_s(
1122             "",
1123             "extern",
1124             "Specify where an external rust library is located",
1125             "NAME[=PATH]",
1126         ),
1127         opt::multi_s(
1128             "",
1129             "extern-location",
1130             "Location where an external crate dependency is specified",
1131             "NAME=LOCATION",
1132         ),
1133         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1134         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1135         opt::opt_s(
1136             "",
1137             "error-format",
1138             "How errors and other messages are produced",
1139             "human|json|short",
1140         ),
1141         opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1142         opt::opt_s(
1143             "",
1144             "color",
1145             "Configure coloring of output:
1146                                  auto   = colorize, if output goes to a tty (default);
1147                                  always = always colorize output;
1148                                  never  = never colorize output",
1149             "auto|always|never",
1150         ),
1151         opt::opt(
1152             "",
1153             "pretty",
1154             "Pretty-print the input instead of compiling;
1155                   valid types are: `normal` (un-annotated source),
1156                   `expanded` (crates expanded), or
1157                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1158             "TYPE",
1159         ),
1160         opt::multi_s(
1161             "",
1162             "remap-path-prefix",
1163             "Remap source names in all output (compiler messages and output files)",
1164             "FROM=TO",
1165         ),
1166     ]);
1167     opts
1168 }
1169
1170 pub fn get_cmd_lint_options(
1171     matches: &getopts::Matches,
1172     error_format: ErrorOutputType,
1173     debugging_opts: &DebuggingOptions,
1174 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1175     let mut lint_opts_with_position = vec![];
1176     let mut describe_lints = false;
1177
1178     if !debugging_opts.unstable_options && matches.opt_present("force-warn") {
1179         early_error(
1180             error_format,
1181             "the `-Z unstable-options` flag must also be passed to enable \
1182             the flag `--force-warn=lints`",
1183         );
1184     }
1185
1186     for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1187         for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1188             if lint_name == "help" {
1189                 describe_lints = true;
1190             } else {
1191                 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1192             }
1193         }
1194     }
1195
1196     lint_opts_with_position.sort_by_key(|x| x.0);
1197     let lint_opts = lint_opts_with_position
1198         .iter()
1199         .cloned()
1200         .map(|(_, lint_name, level)| (lint_name, level))
1201         .collect();
1202
1203     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1204         lint::Level::from_str(&cap)
1205             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1206     });
1207
1208     (lint_opts, describe_lints, lint_cap)
1209 }
1210
1211 /// Parses the `--color` flag.
1212 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1213     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1214         Some("auto") => ColorConfig::Auto,
1215         Some("always") => ColorConfig::Always,
1216         Some("never") => ColorConfig::Never,
1217
1218         None => ColorConfig::Auto,
1219
1220         Some(arg) => early_error(
1221             ErrorOutputType::default(),
1222             &format!(
1223                 "argument for `--color` must be auto, \
1224                  always or never (instead was `{}`)",
1225                 arg
1226             ),
1227         ),
1228     }
1229 }
1230
1231 /// Possible json config files
1232 pub struct JsonConfig {
1233     pub json_rendered: HumanReadableErrorType,
1234     pub json_artifact_notifications: bool,
1235     pub json_unused_externs: bool,
1236 }
1237
1238 /// Parse the `--json` flag.
1239 ///
1240 /// The first value returned is how to render JSON diagnostics, and the second
1241 /// is whether or not artifact notifications are enabled.
1242 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1243     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1244         HumanReadableErrorType::Default;
1245     let mut json_color = ColorConfig::Never;
1246     let mut json_artifact_notifications = false;
1247     let mut json_unused_externs = false;
1248     for option in matches.opt_strs("json") {
1249         // For now conservatively forbid `--color` with `--json` since `--json`
1250         // won't actually be emitting any colors and anything colorized is
1251         // embedded in a diagnostic message anyway.
1252         if matches.opt_str("color").is_some() {
1253             early_error(
1254                 ErrorOutputType::default(),
1255                 "cannot specify the `--color` option with `--json`",
1256             );
1257         }
1258
1259         for sub_option in option.split(',') {
1260             match sub_option {
1261                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1262                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1263                 "artifacts" => json_artifact_notifications = true,
1264                 "unused-externs" => json_unused_externs = true,
1265                 s => early_error(
1266                     ErrorOutputType::default(),
1267                     &format!("unknown `--json` option `{}`", s),
1268                 ),
1269             }
1270         }
1271     }
1272
1273     JsonConfig {
1274         json_rendered: json_rendered(json_color),
1275         json_artifact_notifications,
1276         json_unused_externs,
1277     }
1278 }
1279
1280 /// Parses the `--error-format` flag.
1281 pub fn parse_error_format(
1282     matches: &getopts::Matches,
1283     color: ColorConfig,
1284     json_rendered: HumanReadableErrorType,
1285 ) -> ErrorOutputType {
1286     // We need the `opts_present` check because the driver will send us Matches
1287     // with only stable options if no unstable options are used. Since error-format
1288     // is unstable, it will not be present. We have to use `opts_present` not
1289     // `opt_present` because the latter will panic.
1290     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1291         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1292             None | Some("human") => {
1293                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1294             }
1295             Some("human-annotate-rs") => {
1296                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1297             }
1298             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1299             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1300             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1301
1302             Some(arg) => early_error(
1303                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1304                 &format!(
1305                     "argument for `--error-format` must be `human`, `json` or \
1306                      `short` (instead was `{}`)",
1307                     arg
1308                 ),
1309             ),
1310         }
1311     } else {
1312         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1313     };
1314
1315     match error_format {
1316         ErrorOutputType::Json { .. } => {}
1317
1318         // Conservatively require that the `--json` argument is coupled with
1319         // `--error-format=json`. This means that `--json` is specified we
1320         // should actually be emitting JSON blobs.
1321         _ if !matches.opt_strs("json").is_empty() => {
1322             early_error(
1323                 ErrorOutputType::default(),
1324                 "using `--json` requires also using `--error-format=json`",
1325             );
1326         }
1327
1328         _ => {}
1329     }
1330
1331     error_format
1332 }
1333
1334 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1335     let edition = match matches.opt_str("edition") {
1336         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1337             early_error(
1338                 ErrorOutputType::default(),
1339                 &format!(
1340                     "argument for `--edition` must be one of: \
1341                      {}. (instead was `{}`)",
1342                     EDITION_NAME_LIST, arg
1343                 ),
1344             )
1345         }),
1346         None => DEFAULT_EDITION,
1347     };
1348
1349     if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1350         let is_nightly = nightly_options::match_is_nightly_build(matches);
1351         let msg = if !is_nightly {
1352             format!(
1353                 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1354                 edition, LATEST_STABLE_EDITION
1355             )
1356         } else {
1357             format!("edition {} is unstable and only available with -Z unstable-options", edition)
1358         };
1359         early_error(ErrorOutputType::default(), &msg)
1360     }
1361
1362     edition
1363 }
1364
1365 fn check_debug_option_stability(
1366     debugging_opts: &DebuggingOptions,
1367     error_format: ErrorOutputType,
1368     json_rendered: HumanReadableErrorType,
1369 ) {
1370     if !debugging_opts.unstable_options {
1371         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1372             early_error(
1373                 ErrorOutputType::Json { pretty: false, json_rendered },
1374                 "`--error-format=pretty-json` is unstable",
1375             );
1376         }
1377         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1378             error_format
1379         {
1380             early_error(
1381                 ErrorOutputType::Json { pretty: false, json_rendered },
1382                 "`--error-format=human-annotate-rs` is unstable",
1383             );
1384         }
1385     }
1386 }
1387
1388 fn parse_output_types(
1389     debugging_opts: &DebuggingOptions,
1390     matches: &getopts::Matches,
1391     error_format: ErrorOutputType,
1392 ) -> OutputTypes {
1393     let mut output_types = BTreeMap::new();
1394     if !debugging_opts.parse_only {
1395         for list in matches.opt_strs("emit") {
1396             for output_type in list.split(',') {
1397                 let (shorthand, path) = match output_type.split_once('=') {
1398                     None => (output_type, None),
1399                     Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1400                 };
1401                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1402                     early_error(
1403                         error_format,
1404                         &format!(
1405                             "unknown emission type: `{}` - expected one of: {}",
1406                             shorthand,
1407                             OutputType::shorthands_display(),
1408                         ),
1409                     )
1410                 });
1411                 output_types.insert(output_type, path);
1412             }
1413         }
1414     };
1415     if output_types.is_empty() {
1416         output_types.insert(OutputType::Exe, None);
1417     }
1418     OutputTypes(output_types)
1419 }
1420
1421 fn should_override_cgus_and_disable_thinlto(
1422     output_types: &OutputTypes,
1423     matches: &getopts::Matches,
1424     error_format: ErrorOutputType,
1425     mut codegen_units: Option<usize>,
1426 ) -> (bool, Option<usize>) {
1427     let mut disable_thinlto = false;
1428     // Issue #30063: if user requests LLVM-related output to one
1429     // particular path, disable codegen-units.
1430     let incompatible: Vec<_> = output_types
1431         .0
1432         .iter()
1433         .map(|ot_path| ot_path.0)
1434         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1435         .map(|ot| ot.shorthand())
1436         .collect();
1437     if !incompatible.is_empty() {
1438         match codegen_units {
1439             Some(n) if n > 1 => {
1440                 if matches.opt_present("o") {
1441                     for ot in &incompatible {
1442                         early_warn(
1443                             error_format,
1444                             &format!(
1445                                 "`--emit={}` with `-o` incompatible with \
1446                                  `-C codegen-units=N` for N > 1",
1447                                 ot
1448                             ),
1449                         );
1450                     }
1451                     early_warn(error_format, "resetting to default -C codegen-units=1");
1452                     codegen_units = Some(1);
1453                     disable_thinlto = true;
1454                 }
1455             }
1456             _ => {
1457                 codegen_units = Some(1);
1458                 disable_thinlto = true;
1459             }
1460         }
1461     }
1462
1463     if codegen_units == Some(0) {
1464         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1465     }
1466
1467     (disable_thinlto, codegen_units)
1468 }
1469
1470 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1471     if debugging_opts.threads == 0 {
1472         early_error(error_format, "value for threads must be a positive non-zero integer");
1473     }
1474
1475     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1476         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1477     }
1478 }
1479
1480 fn collect_print_requests(
1481     cg: &mut CodegenOptions,
1482     dopts: &mut DebuggingOptions,
1483     matches: &getopts::Matches,
1484     error_format: ErrorOutputType,
1485 ) -> Vec<PrintRequest> {
1486     let mut prints = Vec::<PrintRequest>::new();
1487     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1488         prints.push(PrintRequest::TargetCPUs);
1489         cg.target_cpu = None;
1490     };
1491     if cg.target_feature == "help" {
1492         prints.push(PrintRequest::TargetFeatures);
1493         cg.target_feature = String::new();
1494     }
1495
1496     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1497         "crate-name" => PrintRequest::CrateName,
1498         "file-names" => PrintRequest::FileNames,
1499         "sysroot" => PrintRequest::Sysroot,
1500         "target-libdir" => PrintRequest::TargetLibdir,
1501         "cfg" => PrintRequest::Cfg,
1502         "target-list" => PrintRequest::TargetList,
1503         "target-cpus" => PrintRequest::TargetCPUs,
1504         "target-features" => PrintRequest::TargetFeatures,
1505         "relocation-models" => PrintRequest::RelocationModels,
1506         "code-models" => PrintRequest::CodeModels,
1507         "tls-models" => PrintRequest::TlsModels,
1508         "native-static-libs" => PrintRequest::NativeStaticLibs,
1509         "target-spec-json" => {
1510             if dopts.unstable_options {
1511                 PrintRequest::TargetSpec
1512             } else {
1513                 early_error(
1514                     error_format,
1515                     "the `-Z unstable-options` flag must also be passed to \
1516                      enable the target-spec-json print option",
1517                 );
1518             }
1519         }
1520         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1521     }));
1522
1523     prints
1524 }
1525
1526 pub fn parse_target_triple(
1527     matches: &getopts::Matches,
1528     error_format: ErrorOutputType,
1529 ) -> TargetTriple {
1530     match matches.opt_str("target") {
1531         Some(target) if target.ends_with(".json") => {
1532             let path = Path::new(&target);
1533             TargetTriple::from_path(&path).unwrap_or_else(|_| {
1534                 early_error(error_format, &format!("target file {:?} does not exist", path))
1535             })
1536         }
1537         Some(target) => TargetTriple::TargetTriple(target),
1538         _ => TargetTriple::from_triple(host_triple()),
1539     }
1540 }
1541
1542 fn parse_opt_level(
1543     matches: &getopts::Matches,
1544     cg: &CodegenOptions,
1545     error_format: ErrorOutputType,
1546 ) -> OptLevel {
1547     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1548     // to use them interchangeably. However, because they're technically different flags,
1549     // we need to work out manually which should take precedence if both are supplied (i.e.
1550     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1551     // comparing them. Note that if a flag is not found, its position will be `None`, which
1552     // always compared less than `Some(_)`.
1553     let max_o = matches.opt_positions("O").into_iter().max();
1554     let max_c = matches
1555         .opt_strs_pos("C")
1556         .into_iter()
1557         .flat_map(|(i, s)| {
1558             // NB: This can match a string without `=`.
1559             if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1560         })
1561         .max();
1562     if max_o > max_c {
1563         OptLevel::Default
1564     } else {
1565         match cg.opt_level.as_ref() {
1566             "0" => OptLevel::No,
1567             "1" => OptLevel::Less,
1568             "2" => OptLevel::Default,
1569             "3" => OptLevel::Aggressive,
1570             "s" => OptLevel::Size,
1571             "z" => OptLevel::SizeMin,
1572             arg => {
1573                 early_error(
1574                     error_format,
1575                     &format!(
1576                         "optimization level needs to be \
1577                             between 0-3, s or z (instead was `{}`)",
1578                         arg
1579                     ),
1580                 );
1581             }
1582         }
1583     }
1584 }
1585
1586 fn select_debuginfo(
1587     matches: &getopts::Matches,
1588     cg: &CodegenOptions,
1589     error_format: ErrorOutputType,
1590 ) -> DebugInfo {
1591     let max_g = matches.opt_positions("g").into_iter().max();
1592     let max_c = matches
1593         .opt_strs_pos("C")
1594         .into_iter()
1595         .flat_map(|(i, s)| {
1596             // NB: This can match a string without `=`.
1597             if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1598         })
1599         .max();
1600     if max_g > max_c {
1601         DebugInfo::Full
1602     } else {
1603         match cg.debuginfo {
1604             0 => DebugInfo::None,
1605             1 => DebugInfo::Limited,
1606             2 => DebugInfo::Full,
1607             arg => {
1608                 early_error(
1609                     error_format,
1610                     &format!(
1611                         "debug info level needs to be between \
1612                          0-2 (instead was `{}`)",
1613                         arg
1614                     ),
1615                 );
1616             }
1617         }
1618     }
1619 }
1620
1621 fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind {
1622     match kind {
1623         "dylib" => NativeLibKind::Dylib { as_needed: None },
1624         "framework" => NativeLibKind::Framework { as_needed: None },
1625         "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1626         "static-nobundle" => {
1627             early_warn(
1628                 error_format,
1629                 "library kind `static-nobundle` has been superseded by specifying \
1630                 `-bundle` on library kind `static`. Try `static:-bundle`",
1631             );
1632             NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1633         }
1634         s => early_error(
1635             error_format,
1636             &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1637         ),
1638     }
1639 }
1640
1641 fn parse_native_lib_modifiers(
1642     is_nightly: bool,
1643     mut kind: NativeLibKind,
1644     modifiers: &str,
1645     error_format: ErrorOutputType,
1646 ) -> (NativeLibKind, Option<bool>) {
1647     let mut verbatim = None;
1648     for modifier in modifiers.split(',') {
1649         let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1650             Some(m) => (m, modifier.starts_with('+')),
1651             None => early_error(
1652                 error_format,
1653                 "invalid linking modifier syntax, expected '+' or '-' prefix \
1654                     before one of: bundle, verbatim, whole-archive, as-needed",
1655             ),
1656         };
1657
1658         if !is_nightly {
1659             early_error(
1660                 error_format,
1661                 "linking modifiers are currently unstable and only accepted on \
1662                 the nightly compiler",
1663             );
1664         }
1665
1666         match (modifier, &mut kind) {
1667             ("bundle", NativeLibKind::Static { bundle, .. }) => {
1668                 *bundle = Some(value);
1669             }
1670             ("bundle", _) => early_error(
1671                 error_format,
1672                 "bundle linking modifier is only compatible with \
1673                     `static` linking kind",
1674             ),
1675
1676             ("verbatim", _) => verbatim = Some(value),
1677
1678             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1679                 *whole_archive = Some(value);
1680             }
1681             ("whole-archive", _) => early_error(
1682                 error_format,
1683                 "whole-archive linking modifier is only compatible with \
1684                     `static` linking kind",
1685             ),
1686
1687             ("as-needed", NativeLibKind::Dylib { as_needed })
1688             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1689                 *as_needed = Some(value);
1690             }
1691             ("as-needed", _) => early_error(
1692                 error_format,
1693                 "as-needed linking modifier is only compatible with \
1694                     `dylib` and `framework` linking kinds",
1695             ),
1696
1697             _ => early_error(
1698                 error_format,
1699                 &format!(
1700                     "unrecognized linking modifier `{}`, expected one \
1701                     of: bundle, verbatim, whole-archive, as-needed",
1702                     modifier
1703                 ),
1704             ),
1705         }
1706     }
1707
1708     (kind, verbatim)
1709 }
1710
1711 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1712     let is_nightly = nightly_options::match_is_nightly_build(matches);
1713     matches
1714         .opt_strs("l")
1715         .into_iter()
1716         .map(|s| {
1717             // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1718             // where KIND is one of "dylib", "framework", "static" and
1719             // where MODIFIERS are  a comma separated list of supported modifiers
1720             // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1721             // with either + or - to indicate whether it is enabled or disabled.
1722             // The last value specified for a given modifier wins.
1723             let (name, kind, verbatim) = match s.split_once('=') {
1724                 None => (s, NativeLibKind::Unspecified, None),
1725                 Some((kind, name)) => {
1726                     let (kind, verbatim) = match kind.split_once(':') {
1727                         None => (parse_native_lib_kind(kind, error_format), None),
1728                         Some((kind, modifiers)) => {
1729                             let kind = parse_native_lib_kind(kind, error_format);
1730                             parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format)
1731                         }
1732                     };
1733                     (name.to_string(), kind, verbatim)
1734                 }
1735             };
1736
1737             let (name, new_name) = match name.split_once(':') {
1738                 None => (name, None),
1739                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1740             };
1741             NativeLib { name, new_name, kind, verbatim }
1742         })
1743         .collect()
1744 }
1745
1746 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1747     match dopts.borrowck.as_ref() {
1748         "migrate" => BorrowckMode::Migrate,
1749         "mir" => BorrowckMode::Mir,
1750         m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1751     }
1752 }
1753
1754 pub fn parse_externs(
1755     matches: &getopts::Matches,
1756     debugging_opts: &DebuggingOptions,
1757     error_format: ErrorOutputType,
1758 ) -> Externs {
1759     let is_unstable_enabled = debugging_opts.unstable_options;
1760     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1761     for arg in matches.opt_strs("extern") {
1762         let (name, path) = match arg.split_once('=') {
1763             None => (arg, None),
1764             Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1765         };
1766         let (options, name) = match name.split_once(':') {
1767             None => (None, name),
1768             Some((opts, name)) => (Some(opts), name.to_string()),
1769         };
1770
1771         let path = path.map(|p| CanonicalizedPath::new(p));
1772
1773         let entry = externs.entry(name.to_owned());
1774
1775         use std::collections::btree_map::Entry;
1776
1777         let entry = if let Some(path) = path {
1778             // --extern prelude_name=some_file.rlib
1779             match entry {
1780                 Entry::Vacant(vacant) => {
1781                     let files = BTreeSet::from_iter(iter::once(path));
1782                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1783                 }
1784                 Entry::Occupied(occupied) => {
1785                     let ext_ent = occupied.into_mut();
1786                     match ext_ent {
1787                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1788                             files.insert(path);
1789                         }
1790                         ExternEntry {
1791                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1792                             ..
1793                         } => {
1794                             // Exact paths take precedence over search directories.
1795                             let files = BTreeSet::from_iter(iter::once(path));
1796                             *location = ExternLocation::ExactPaths(files);
1797                         }
1798                     }
1799                     ext_ent
1800                 }
1801             }
1802         } else {
1803             // --extern prelude_name
1804             match entry {
1805                 Entry::Vacant(vacant) => {
1806                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1807                 }
1808                 Entry::Occupied(occupied) => {
1809                     // Ignore if already specified.
1810                     occupied.into_mut()
1811                 }
1812             }
1813         };
1814
1815         let mut is_private_dep = false;
1816         let mut add_prelude = true;
1817         if let Some(opts) = options {
1818             if !is_unstable_enabled {
1819                 early_error(
1820                     error_format,
1821                     "the `-Z unstable-options` flag must also be passed to \
1822                      enable `--extern options",
1823                 );
1824             }
1825             for opt in opts.split(',') {
1826                 match opt {
1827                     "priv" => is_private_dep = true,
1828                     "noprelude" => {
1829                         if let ExternLocation::ExactPaths(_) = &entry.location {
1830                             add_prelude = false;
1831                         } else {
1832                             early_error(
1833                                 error_format,
1834                                 "the `noprelude` --extern option requires a file path",
1835                             );
1836                         }
1837                     }
1838                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1839                 }
1840             }
1841         }
1842
1843         // Crates start out being not private, and go to being private `priv`
1844         // is specified.
1845         entry.is_private_dep |= is_private_dep;
1846         // If any flag is missing `noprelude`, then add to the prelude.
1847         entry.add_prelude |= add_prelude;
1848     }
1849     Externs(externs)
1850 }
1851
1852 fn parse_extern_dep_specs(
1853     matches: &getopts::Matches,
1854     debugging_opts: &DebuggingOptions,
1855     error_format: ErrorOutputType,
1856 ) -> ExternDepSpecs {
1857     let is_unstable_enabled = debugging_opts.unstable_options;
1858     let mut map = BTreeMap::new();
1859
1860     for arg in matches.opt_strs("extern-location") {
1861         if !is_unstable_enabled {
1862             early_error(
1863                 error_format,
1864                 "`--extern-location` option is unstable: set `-Z unstable-options`",
1865             );
1866         }
1867
1868         let mut parts = arg.splitn(2, '=');
1869         let name = parts.next().unwrap_or_else(|| {
1870             early_error(error_format, "`--extern-location` value must not be empty")
1871         });
1872         let loc = parts.next().unwrap_or_else(|| {
1873             early_error(
1874                 error_format,
1875                 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1876             )
1877         });
1878
1879         let locparts: Vec<_> = loc.split(":").collect();
1880         let spec = match &locparts[..] {
1881             ["raw", ..] => {
1882                 // Don't want `:` split string
1883                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1884                     early_error(error_format, "`--extern-location`: missing `raw` location")
1885                 });
1886                 ExternDepSpec::Raw(raw.to_string())
1887             }
1888             ["json", ..] => {
1889                 // Don't want `:` split string
1890                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1891                     early_error(error_format, "`--extern-location`: missing `json` location")
1892                 });
1893                 let json = json::from_str(raw).unwrap_or_else(|_| {
1894                     early_error(
1895                         error_format,
1896                         &format!("`--extern-location`: malformed json location `{}`", raw),
1897                     )
1898                 });
1899                 ExternDepSpec::Json(json)
1900             }
1901             [bad, ..] => early_error(
1902                 error_format,
1903                 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1904             ),
1905             [] => early_error(error_format, "missing location specification"),
1906         };
1907
1908         map.insert(name.to_string(), spec);
1909     }
1910
1911     ExternDepSpecs::new(map)
1912 }
1913
1914 fn parse_remap_path_prefix(
1915     matches: &getopts::Matches,
1916     error_format: ErrorOutputType,
1917 ) -> Vec<(PathBuf, PathBuf)> {
1918     matches
1919         .opt_strs("remap-path-prefix")
1920         .into_iter()
1921         .map(|remap| match remap.rsplit_once('=') {
1922             None => early_error(
1923                 error_format,
1924                 "--remap-path-prefix must contain '=' between FROM and TO",
1925             ),
1926             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1927         })
1928         .collect()
1929 }
1930
1931 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1932     let color = parse_color(matches);
1933
1934     let edition = parse_crate_edition(matches);
1935
1936     let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1937         parse_json(matches);
1938
1939     let error_format = parse_error_format(matches, color, json_rendered);
1940
1941     let unparsed_crate_types = matches.opt_strs("crate-type");
1942     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1943         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1944
1945     let mut debugging_opts = DebuggingOptions::build(matches, error_format);
1946     let (lint_opts, describe_lints, lint_cap) =
1947         get_cmd_lint_options(matches, error_format, &debugging_opts);
1948
1949     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1950
1951     if !debugging_opts.unstable_options && json_unused_externs {
1952         early_error(
1953             error_format,
1954             "the `-Z unstable-options` flag must also be passed to enable \
1955             the flag `--json=unused-externs`",
1956         );
1957     }
1958
1959     let output_types = parse_output_types(&debugging_opts, matches, error_format);
1960
1961     let mut cg = CodegenOptions::build(matches, error_format);
1962     let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1963         &output_types,
1964         matches,
1965         error_format,
1966         cg.codegen_units,
1967     );
1968
1969     check_thread_count(&debugging_opts, error_format);
1970
1971     let incremental = cg.incremental.as_ref().map(PathBuf::from);
1972
1973     if debugging_opts.profile && incremental.is_some() {
1974         early_error(
1975             error_format,
1976             "can't instrument with gcov profiling when compiling incrementally",
1977         );
1978     }
1979     if debugging_opts.profile {
1980         match codegen_units {
1981             Some(1) => {}
1982             None => codegen_units = Some(1),
1983             Some(_) => early_error(
1984                 error_format,
1985                 "can't instrument with gcov profiling with multiple codegen units",
1986             ),
1987         }
1988     }
1989
1990     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1991         early_error(
1992             error_format,
1993             "options `-C profile-generate` and `-C profile-use` are exclusive",
1994         );
1995     }
1996
1997     if debugging_opts.instrument_coverage.is_some()
1998         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1999     {
2000         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2001             early_error(
2002                 error_format,
2003                 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2004                 or `-C profile-generate`",
2005             );
2006         }
2007
2008         // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2009         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2010         // multiple runs, including some changes to source code; so mangled names must be consistent
2011         // across compilations.
2012         match debugging_opts.symbol_mangling_version {
2013             None => {
2014                 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2015             }
2016             Some(SymbolManglingVersion::Legacy) => {
2017                 early_warn(
2018                     error_format,
2019                     "-Z instrument-coverage requires symbol mangling version `v0`, \
2020                     but `-Z symbol-mangling-version=legacy` was specified",
2021                 );
2022             }
2023             Some(SymbolManglingVersion::V0) => {}
2024         }
2025     }
2026
2027     if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2028         debugging_opts.graphviz_font = graphviz_font;
2029     }
2030
2031     if !cg.embed_bitcode {
2032         match cg.lto {
2033             LtoCli::No | LtoCli::Unspecified => {}
2034             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2035                 error_format,
2036                 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2037             ),
2038         }
2039     }
2040
2041     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2042
2043     let cg = cg;
2044
2045     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2046     let target_triple = parse_target_triple(matches, error_format);
2047     let opt_level = parse_opt_level(matches, &cg, error_format);
2048     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2049     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2050     // for more details.
2051     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2052     let debuginfo = select_debuginfo(matches, &cg, error_format);
2053
2054     let mut search_paths = vec![];
2055     for s in &matches.opt_strs("L") {
2056         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2057     }
2058
2059     let libs = parse_libs(matches, error_format);
2060
2061     let test = matches.opt_present("test");
2062
2063     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2064
2065     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2066         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2067     }
2068
2069     let externs = parse_externs(matches, &debugging_opts, error_format);
2070     let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2071
2072     let crate_name = matches.opt_str("crate-name");
2073
2074     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2075
2076     let pretty = parse_pretty(matches, &debugging_opts, error_format);
2077
2078     if !debugging_opts.unstable_options
2079         && !target_triple.triple().contains("apple")
2080         && cg.split_debuginfo.is_some()
2081     {
2082         {
2083             early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2084         }
2085     }
2086
2087     // Try to find a directory containing the Rust `src`, for more details see
2088     // the doc comment on the `real_rust_source_base_dir` field.
2089     let tmp_buf;
2090     let sysroot = match &sysroot_opt {
2091         Some(s) => s,
2092         None => {
2093             tmp_buf = crate::filesearch::get_or_default_sysroot();
2094             &tmp_buf
2095         }
2096     };
2097     let real_rust_source_base_dir = {
2098         // This is the location used by the `rust-src` `rustup` component.
2099         let mut candidate = sysroot.join("lib/rustlib/src/rust");
2100         if let Ok(metadata) = candidate.symlink_metadata() {
2101             // Replace the symlink rustbuild creates, with its destination.
2102             // We could try to use `fs::canonicalize` instead, but that might
2103             // produce unnecessarily verbose path.
2104             if metadata.file_type().is_symlink() {
2105                 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2106                     candidate = symlink_dest;
2107                 }
2108             }
2109         }
2110
2111         // Only use this directory if it has a file we can expect to always find.
2112         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2113     };
2114
2115     Options {
2116         crate_types,
2117         optimize: opt_level,
2118         debuginfo,
2119         lint_opts,
2120         lint_cap,
2121         describe_lints,
2122         output_types,
2123         search_paths,
2124         maybe_sysroot: sysroot_opt,
2125         target_triple,
2126         test,
2127         incremental,
2128         debugging_opts,
2129         prints,
2130         borrowck_mode,
2131         cg,
2132         error_format,
2133         externs,
2134         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2135         extern_dep_specs,
2136         crate_name,
2137         alt_std_name: None,
2138         libs,
2139         debug_assertions,
2140         actually_rustdoc: false,
2141         trimmed_def_paths: TrimmedDefPaths::default(),
2142         cli_forced_codegen_units: codegen_units,
2143         cli_forced_thinlto_off: disable_thinlto,
2144         remap_path_prefix,
2145         real_rust_source_base_dir,
2146         edition,
2147         json_artifact_notifications,
2148         json_unused_externs,
2149         pretty,
2150     }
2151 }
2152
2153 fn parse_pretty(
2154     matches: &getopts::Matches,
2155     debugging_opts: &DebuggingOptions,
2156     efmt: ErrorOutputType,
2157 ) -> Option<PpMode> {
2158     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2159         use PpMode::*;
2160         let first = match (name, extended) {
2161             ("normal", _) => Source(PpSourceMode::Normal),
2162             ("identified", _) => Source(PpSourceMode::Identified),
2163             ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2164             ("expanded", _) => Source(PpSourceMode::Expanded),
2165             ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2166             ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2167             ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2168             ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2169             ("hir", true) => Hir(PpHirMode::Normal),
2170             ("hir,identified", true) => Hir(PpHirMode::Identified),
2171             ("hir,typed", true) => Hir(PpHirMode::Typed),
2172             ("hir-tree", true) => HirTree,
2173             ("thir-tree", true) => ThirTree,
2174             ("mir", true) => Mir,
2175             ("mir-cfg", true) => MirCFG,
2176             _ => {
2177                 if extended {
2178                     early_error(
2179                         efmt,
2180                         &format!(
2181                             "argument to `unpretty` must be one of `normal`, \
2182                                         `expanded`, `identified`, `expanded,identified`, \
2183                                         `expanded,hygiene`, `everybody_loops`, \
2184                                         `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2185                                         `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2186                             name
2187                         ),
2188                     );
2189                 } else {
2190                     early_error(
2191                         efmt,
2192                         &format!(
2193                             "argument to `pretty` must be one of `normal`, \
2194                                         `expanded`, `identified`, or `expanded,identified`; got {}",
2195                             name
2196                         ),
2197                     );
2198                 }
2199             }
2200         };
2201         tracing::debug!("got unpretty option: {:?}", first);
2202         first
2203     }
2204
2205     if debugging_opts.unstable_options {
2206         if let Some(a) = matches.opt_default("pretty", "normal") {
2207             // stable pretty-print variants only
2208             return Some(parse_pretty_inner(efmt, &a, false));
2209         }
2210     }
2211
2212     debugging_opts.unpretty.as_ref().map(|a| {
2213         // extended with unstable pretty-print variants
2214         parse_pretty_inner(efmt, &a, true)
2215     })
2216 }
2217
2218 pub fn make_crate_type_option() -> RustcOptGroup {
2219     opt::multi_s(
2220         "",
2221         "crate-type",
2222         "Comma separated list of types of crates
2223                                 for the compiler to emit",
2224         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2225     )
2226 }
2227
2228 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2229     let mut crate_types: Vec<CrateType> = Vec::new();
2230     for unparsed_crate_type in &list_list {
2231         for part in unparsed_crate_type.split(',') {
2232             let new_part = match part {
2233                 "lib" => default_lib_output(),
2234                 "rlib" => CrateType::Rlib,
2235                 "staticlib" => CrateType::Staticlib,
2236                 "dylib" => CrateType::Dylib,
2237                 "cdylib" => CrateType::Cdylib,
2238                 "bin" => CrateType::Executable,
2239                 "proc-macro" => CrateType::ProcMacro,
2240                 _ => return Err(format!("unknown crate type: `{}`", part)),
2241             };
2242             if !crate_types.contains(&new_part) {
2243                 crate_types.push(new_part)
2244             }
2245         }
2246     }
2247
2248     Ok(crate_types)
2249 }
2250
2251 pub mod nightly_options {
2252     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2253     use crate::early_error;
2254     use rustc_feature::UnstableFeatures;
2255
2256     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2257         match_is_nightly_build(matches)
2258             && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2259     }
2260
2261     pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2262         is_nightly_build(matches.opt_str("crate-name").as_deref())
2263     }
2264
2265     pub fn is_nightly_build(krate: Option<&str>) -> bool {
2266         UnstableFeatures::from_environment(krate).is_nightly_build()
2267     }
2268
2269     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2270         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2271         let really_allows_unstable_options = match_is_nightly_build(matches);
2272
2273         for opt in flags.iter() {
2274             if opt.stability == OptionStability::Stable {
2275                 continue;
2276             }
2277             if !matches.opt_present(opt.name) {
2278                 continue;
2279             }
2280             if opt.name != "Z" && !has_z_unstable_option {
2281                 early_error(
2282                     ErrorOutputType::default(),
2283                     &format!(
2284                         "the `-Z unstable-options` flag must also be passed to enable \
2285                          the flag `{}`",
2286                         opt.name
2287                     ),
2288                 );
2289             }
2290             if really_allows_unstable_options {
2291                 continue;
2292             }
2293             match opt.stability {
2294                 OptionStability::Unstable => {
2295                     let msg = format!(
2296                         "the option `{}` is only accepted on the \
2297                          nightly compiler",
2298                         opt.name
2299                     );
2300                     early_error(ErrorOutputType::default(), &msg);
2301                 }
2302                 OptionStability::Stable => {}
2303             }
2304         }
2305     }
2306 }
2307
2308 impl fmt::Display for CrateType {
2309     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2310         match *self {
2311             CrateType::Executable => "bin".fmt(f),
2312             CrateType::Dylib => "dylib".fmt(f),
2313             CrateType::Rlib => "rlib".fmt(f),
2314             CrateType::Staticlib => "staticlib".fmt(f),
2315             CrateType::Cdylib => "cdylib".fmt(f),
2316             CrateType::ProcMacro => "proc-macro".fmt(f),
2317         }
2318     }
2319 }
2320
2321 #[derive(Copy, Clone, PartialEq, Debug)]
2322 pub enum PpSourceMode {
2323     /// `--pretty=normal`
2324     Normal,
2325     /// `-Zunpretty=everybody_loops`
2326     EveryBodyLoops,
2327     /// `--pretty=expanded`
2328     Expanded,
2329     /// `--pretty=identified`
2330     Identified,
2331     /// `--pretty=expanded,identified`
2332     ExpandedIdentified,
2333     /// `--pretty=expanded,hygiene`
2334     ExpandedHygiene,
2335 }
2336
2337 #[derive(Copy, Clone, PartialEq, Debug)]
2338 pub enum PpAstTreeMode {
2339     /// `-Zunpretty=ast`
2340     Normal,
2341     /// `-Zunpretty=ast,expanded`
2342     Expanded,
2343 }
2344
2345 #[derive(Copy, Clone, PartialEq, Debug)]
2346 pub enum PpHirMode {
2347     /// `-Zunpretty=hir`
2348     Normal,
2349     /// `-Zunpretty=hir,identified`
2350     Identified,
2351     /// `-Zunpretty=hir,typed`
2352     Typed,
2353 }
2354
2355 #[derive(Copy, Clone, PartialEq, Debug)]
2356 pub enum PpMode {
2357     /// Options that print the source code, i.e.
2358     /// `--pretty` and `-Zunpretty=everybody_loops`
2359     Source(PpSourceMode),
2360     AstTree(PpAstTreeMode),
2361     /// Options that print the HIR, i.e. `-Zunpretty=hir`
2362     Hir(PpHirMode),
2363     /// `-Zunpretty=hir-tree`
2364     HirTree,
2365     /// `-Zunpretty=thir-tree`
2366     ThirTree,
2367     /// `-Zunpretty=mir`
2368     Mir,
2369     /// `-Zunpretty=mir-cfg`
2370     MirCFG,
2371 }
2372
2373 impl PpMode {
2374     pub fn needs_ast_map(&self) -> bool {
2375         use PpMode::*;
2376         use PpSourceMode::*;
2377         match *self {
2378             Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2379
2380             Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2381             | AstTree(PpAstTreeMode::Expanded)
2382             | Hir(_)
2383             | HirTree
2384             | ThirTree
2385             | Mir
2386             | MirCFG => true,
2387         }
2388     }
2389
2390     pub fn needs_analysis(&self) -> bool {
2391         use PpMode::*;
2392         matches!(*self, Mir | MirCFG | ThirTree)
2393     }
2394 }
2395
2396 /// Command-line arguments passed to the compiler have to be incorporated with
2397 /// the dependency tracking system for incremental compilation. This module
2398 /// provides some utilities to make this more convenient.
2399 ///
2400 /// The values of all command-line arguments that are relevant for dependency
2401 /// tracking are hashed into a single value that determines whether the
2402 /// incremental compilation cache can be re-used or not. This hashing is done
2403 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2404 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2405 /// the hash of which is order dependent, but we might not want the order of
2406 /// arguments to make a difference for the hash).
2407 ///
2408 /// However, since the value provided by `Hash::hash` often *is* suitable,
2409 /// especially for primitive types, there is the
2410 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2411 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2412 /// we have an opt-in scheme here, so one is hopefully forced to think about
2413 /// how the hash should be calculated when adding a new command-line argument.
2414 crate mod dep_tracking {
2415     use super::LdImpl;
2416     use super::{
2417         CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2418         LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2419         SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2420     };
2421     use crate::lint;
2422     use crate::options::WasiExecModel;
2423     use crate::utils::{NativeLib, NativeLibKind};
2424     use rustc_feature::UnstableFeatures;
2425     use rustc_span::edition::Edition;
2426     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2427     use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2428     use std::collections::hash_map::DefaultHasher;
2429     use std::collections::BTreeMap;
2430     use std::hash::Hash;
2431     use std::num::NonZeroUsize;
2432     use std::path::PathBuf;
2433
2434     pub trait DepTrackingHash {
2435         fn hash(
2436             &self,
2437             hasher: &mut DefaultHasher,
2438             error_format: ErrorOutputType,
2439             for_crate_hash: bool,
2440         );
2441     }
2442
2443     macro_rules! impl_dep_tracking_hash_via_hash {
2444         ($($t:ty),+ $(,)?) => {$(
2445             impl DepTrackingHash for $t {
2446                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2447                     Hash::hash(self, hasher);
2448                 }
2449             }
2450         )+};
2451     }
2452
2453     impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2454         fn hash(
2455             &self,
2456             hasher: &mut DefaultHasher,
2457             error_format: ErrorOutputType,
2458             for_crate_hash: bool,
2459         ) {
2460             match self {
2461                 Some(x) => {
2462                     Hash::hash(&1, hasher);
2463                     DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2464                 }
2465                 None => Hash::hash(&0, hasher),
2466             }
2467         }
2468     }
2469
2470     impl_dep_tracking_hash_via_hash!(
2471         bool,
2472         usize,
2473         NonZeroUsize,
2474         u64,
2475         String,
2476         PathBuf,
2477         lint::Level,
2478         WasiExecModel,
2479         u32,
2480         RelocModel,
2481         CodeModel,
2482         TlsModel,
2483         InstrumentCoverage,
2484         CrateType,
2485         MergeFunctions,
2486         PanicStrategy,
2487         RelroLevel,
2488         Passes,
2489         OptLevel,
2490         LtoCli,
2491         DebugInfo,
2492         UnstableFeatures,
2493         NativeLib,
2494         NativeLibKind,
2495         SanitizerSet,
2496         CFGuard,
2497         TargetTriple,
2498         Edition,
2499         LinkerPluginLto,
2500         SplitDebuginfo,
2501         SwitchWithOptPath,
2502         SymbolManglingVersion,
2503         SourceFileHashAlgorithm,
2504         TrimmedDefPaths,
2505         Option<LdImpl>,
2506         OutputType,
2507     );
2508
2509     impl<T1, T2> DepTrackingHash for (T1, T2)
2510     where
2511         T1: DepTrackingHash,
2512         T2: DepTrackingHash,
2513     {
2514         fn hash(
2515             &self,
2516             hasher: &mut DefaultHasher,
2517             error_format: ErrorOutputType,
2518             for_crate_hash: bool,
2519         ) {
2520             Hash::hash(&0, hasher);
2521             DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2522             Hash::hash(&1, hasher);
2523             DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2524         }
2525     }
2526
2527     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2528     where
2529         T1: DepTrackingHash,
2530         T2: DepTrackingHash,
2531         T3: DepTrackingHash,
2532     {
2533         fn hash(
2534             &self,
2535             hasher: &mut DefaultHasher,
2536             error_format: ErrorOutputType,
2537             for_crate_hash: bool,
2538         ) {
2539             Hash::hash(&0, hasher);
2540             DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2541             Hash::hash(&1, hasher);
2542             DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2543             Hash::hash(&2, hasher);
2544             DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2545         }
2546     }
2547
2548     impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2549         fn hash(
2550             &self,
2551             hasher: &mut DefaultHasher,
2552             error_format: ErrorOutputType,
2553             for_crate_hash: bool,
2554         ) {
2555             Hash::hash(&self.len(), hasher);
2556             for (index, elem) in self.iter().enumerate() {
2557                 Hash::hash(&index, hasher);
2558                 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2559             }
2560         }
2561     }
2562
2563     impl DepTrackingHash for OutputTypes {
2564         fn hash(
2565             &self,
2566             hasher: &mut DefaultHasher,
2567             error_format: ErrorOutputType,
2568             for_crate_hash: bool,
2569         ) {
2570             Hash::hash(&self.0.len(), hasher);
2571             for (key, val) in &self.0 {
2572                 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2573                 if !for_crate_hash {
2574                     DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2575                 }
2576             }
2577         }
2578     }
2579
2580     // This is a stable hash because BTreeMap is a sorted container
2581     crate fn stable_hash(
2582         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2583         hasher: &mut DefaultHasher,
2584         error_format: ErrorOutputType,
2585         for_crate_hash: bool,
2586     ) {
2587         for (key, sub_hash) in sub_hashes {
2588             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2589             // the keys, as they are just plain strings
2590             Hash::hash(&key.len(), hasher);
2591             Hash::hash(key, hasher);
2592             sub_hash.hash(hasher, error_format, for_crate_hash);
2593         }
2594     }
2595 }