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