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