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