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