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