]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/config.rs
58113bb8cd6cb430a202d7d9c0a3559b4fa8ad1e
[rust.git] / src / librustc_session / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 use crate::lint;
5 use crate::utils::NativeLibraryKind;
6 use crate::{early_error, early_warn, Session};
7 use crate::search_paths::SearchPath;
8
9 use rustc_data_structures::fx::FxHashSet;
10 use rustc_data_structures::impl_stable_hash_via_hash;
11
12 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
13 use rustc_target::spec::{Target, TargetTriple};
14
15 use syntax_pos::source_map::{FileName, FilePathMapping};
16 use syntax_pos::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
17 use syntax_pos::symbol::{sym, Symbol};
18 use rustc_feature::UnstableFeatures;
19 use crate::parse::CrateConfig;
20
21 use rustc_errors::emitter::HumanReadableErrorType;
22 use rustc_errors::{ColorConfig, FatalError, Handler};
23
24 use getopts;
25
26 use std::collections::{BTreeMap, BTreeSet};
27 use std::collections::btree_map::{
28     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
29 };
30 use std::fmt;
31 use std::str::{self, FromStr};
32 use std::hash::Hasher;
33 use std::collections::hash_map::DefaultHasher;
34 use std::iter::FromIterator;
35 use std::path::{Path, PathBuf};
36
37 pub struct Config {
38     pub target: Target,
39     pub ptr_width: u32,
40 }
41
42 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
43 pub enum Sanitizer {
44     Address,
45     Leak,
46     Memory,
47     Thread,
48 }
49
50 impl fmt::Display for Sanitizer {
51     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52         match *self {
53             Sanitizer::Address => "address".fmt(f),
54             Sanitizer::Leak => "leak".fmt(f),
55             Sanitizer::Memory => "memory".fmt(f),
56             Sanitizer::Thread => "thread".fmt(f),
57         }
58     }
59 }
60
61 impl FromStr for Sanitizer {
62     type Err = ();
63     fn from_str(s: &str) -> Result<Sanitizer, ()> {
64         match s {
65             "address" => Ok(Sanitizer::Address),
66             "leak" => Ok(Sanitizer::Leak),
67             "memory" => Ok(Sanitizer::Memory),
68             "thread" => Ok(Sanitizer::Thread),
69             _ => Err(()),
70         }
71     }
72 }
73
74 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
75 pub enum OptLevel {
76     No,         // -O0
77     Less,       // -O1
78     Default,    // -O2
79     Aggressive, // -O3
80     Size,       // -Os
81     SizeMin,    // -Oz
82 }
83
84 impl_stable_hash_via_hash!(OptLevel);
85
86 /// This is what the `LtoCli` values get mapped to after resolving defaults and
87 /// and taking other command line options into account.
88 #[derive(Clone, PartialEq)]
89 pub enum Lto {
90     /// Don't do any LTO whatsoever
91     No,
92
93     /// Do a full crate graph LTO with ThinLTO
94     Thin,
95
96     /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
97     /// units).
98     ThinLocal,
99
100     /// Do a full crate graph LTO with "fat" LTO
101     Fat,
102 }
103
104 /// The different settings that the `-C lto` flag can have.
105 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
106 pub enum LtoCli {
107     /// `-C lto=no`
108     No,
109     /// `-C lto=yes`
110     Yes,
111     /// `-C lto`
112     NoParam,
113     /// `-C lto=thin`
114     Thin,
115     /// `-C lto=fat`
116     Fat,
117     /// No `-C lto` flag passed
118     Unspecified,
119 }
120
121 #[derive(Clone, PartialEq, Hash)]
122 pub enum LinkerPluginLto {
123     LinkerPlugin(PathBuf),
124     LinkerPluginAuto,
125     Disabled
126 }
127
128 impl LinkerPluginLto {
129     pub fn enabled(&self) -> bool {
130         match *self {
131             LinkerPluginLto::LinkerPlugin(_) |
132             LinkerPluginLto::LinkerPluginAuto => true,
133             LinkerPluginLto::Disabled => false,
134         }
135     }
136 }
137
138 #[derive(Clone, PartialEq, Hash)]
139 pub enum SwitchWithOptPath {
140     Enabled(Option<PathBuf>),
141     Disabled,
142 }
143
144 impl SwitchWithOptPath {
145     pub fn enabled(&self) -> bool {
146         match *self {
147             SwitchWithOptPath::Enabled(_) => true,
148             SwitchWithOptPath::Disabled => false,
149         }
150     }
151 }
152
153 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
154 pub enum SymbolManglingVersion {
155     Legacy,
156     V0,
157 }
158
159 impl_stable_hash_via_hash!(SymbolManglingVersion);
160
161 #[derive(Clone, Copy, PartialEq, Hash)]
162 pub enum DebugInfo {
163     None,
164     Limited,
165     Full,
166 }
167
168 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
169 pub enum OutputType {
170     Bitcode,
171     Assembly,
172     LlvmAssembly,
173     Mir,
174     Metadata,
175     Object,
176     Exe,
177     DepInfo,
178 }
179
180 impl_stable_hash_via_hash!(OutputType);
181
182 impl OutputType {
183     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
184         match *self {
185             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
186             OutputType::Bitcode
187             | OutputType::Assembly
188             | OutputType::LlvmAssembly
189             | OutputType::Mir
190             | OutputType::Object => false,
191         }
192     }
193
194     fn shorthand(&self) -> &'static str {
195         match *self {
196             OutputType::Bitcode => "llvm-bc",
197             OutputType::Assembly => "asm",
198             OutputType::LlvmAssembly => "llvm-ir",
199             OutputType::Mir => "mir",
200             OutputType::Object => "obj",
201             OutputType::Metadata => "metadata",
202             OutputType::Exe => "link",
203             OutputType::DepInfo => "dep-info",
204         }
205     }
206
207     fn from_shorthand(shorthand: &str) -> Option<Self> {
208         Some(match shorthand {
209             "asm" => OutputType::Assembly,
210             "llvm-ir" => OutputType::LlvmAssembly,
211             "mir" => OutputType::Mir,
212             "llvm-bc" => OutputType::Bitcode,
213             "obj" => OutputType::Object,
214             "metadata" => OutputType::Metadata,
215             "link" => OutputType::Exe,
216             "dep-info" => OutputType::DepInfo,
217             _ => return None,
218         })
219     }
220
221     fn shorthands_display() -> String {
222         format!(
223             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
224             OutputType::Bitcode.shorthand(),
225             OutputType::Assembly.shorthand(),
226             OutputType::LlvmAssembly.shorthand(),
227             OutputType::Mir.shorthand(),
228             OutputType::Object.shorthand(),
229             OutputType::Metadata.shorthand(),
230             OutputType::Exe.shorthand(),
231             OutputType::DepInfo.shorthand(),
232         )
233     }
234
235     pub fn extension(&self) -> &'static str {
236         match *self {
237             OutputType::Bitcode => "bc",
238             OutputType::Assembly => "s",
239             OutputType::LlvmAssembly => "ll",
240             OutputType::Mir => "mir",
241             OutputType::Object => "o",
242             OutputType::Metadata => "rmeta",
243             OutputType::DepInfo => "d",
244             OutputType::Exe => "",
245         }
246     }
247 }
248
249 /// The type of diagnostics output to generate.
250 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
251 pub enum ErrorOutputType {
252     /// Output meant for the consumption of humans.
253     HumanReadable(HumanReadableErrorType),
254     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
255     Json {
256         /// Render the JSON in a human readable way (with indents and newlines).
257         pretty: bool,
258         /// The JSON output includes a `rendered` field that includes the rendered
259         /// human output.
260         json_rendered: HumanReadableErrorType,
261     },
262 }
263
264 impl Default for ErrorOutputType {
265     fn default() -> Self {
266         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
267     }
268 }
269
270 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
271 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
272 /// dependency tracking for command-line arguments.
273 #[derive(Clone, Hash)]
274 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
275
276 impl_stable_hash_via_hash!(OutputTypes);
277
278 impl OutputTypes {
279     pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
280         OutputTypes(BTreeMap::from_iter(
281             entries.iter().map(|&(k, ref v)| (k, v.clone())),
282         ))
283     }
284
285     pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
286         self.0.get(key)
287     }
288
289     pub fn contains_key(&self, key: &OutputType) -> bool {
290         self.0.contains_key(key)
291     }
292
293     pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
294         self.0.keys()
295     }
296
297     pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
298         self.0.values()
299     }
300
301     pub fn len(&self) -> usize {
302         self.0.len()
303     }
304
305     // Returns `true` if any of the output types require codegen or linking.
306     pub fn should_codegen(&self) -> bool {
307         self.0.keys().any(|k| match *k {
308             OutputType::Bitcode
309             | OutputType::Assembly
310             | OutputType::LlvmAssembly
311             | OutputType::Mir
312             | OutputType::Object
313             | OutputType::Exe => true,
314             OutputType::Metadata | OutputType::DepInfo => false,
315         })
316     }
317 }
318
319 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
320 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
321 /// would break dependency tracking for command-line arguments.
322 #[derive(Clone)]
323 pub struct Externs(BTreeMap<String, ExternEntry>);
324
325 #[derive(Clone, Debug, Default)]
326 pub struct ExternEntry {
327     pub locations: BTreeSet<Option<String>>,
328     pub is_private_dep: bool
329 }
330
331 impl Externs {
332     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
333         Externs(data)
334     }
335
336     pub fn get(&self, key: &str) -> Option<&ExternEntry> {
337         self.0.get(key)
338     }
339
340     pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
341         self.0.iter()
342     }
343 }
344
345
346 macro_rules! hash_option {
347     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
348     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
349         if $sub_hashes.insert(stringify!($opt_name),
350                               $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
351             panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
352         }
353     });
354 }
355
356 macro_rules! top_level_options {
357     (pub struct Options { $(
358         $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
359     )* } ) => (
360         #[derive(Clone)]
361         pub struct Options {
362             $(pub $opt: $t),*
363         }
364
365         impl Options {
366             pub fn dep_tracking_hash(&self) -> u64 {
367                 let mut sub_hashes = BTreeMap::new();
368                 $({
369                     hash_option!($opt,
370                                  &self.$opt,
371                                  &mut sub_hashes,
372                                  [$dep_tracking_marker $($warn_val,
373                                                          $warn_text,
374                                                          self.error_format)*]);
375                 })*
376                 let mut hasher = DefaultHasher::new();
377                 dep_tracking::stable_hash(sub_hashes,
378                                           &mut hasher,
379                                           self.error_format);
380                 hasher.finish()
381             }
382         }
383     );
384 }
385
386 // The top-level command-line options struct.
387 //
388 // For each option, one has to specify how it behaves with regard to the
389 // dependency tracking system of incremental compilation. This is done via the
390 // square-bracketed directive after the field type. The options are:
391 //
392 // [TRACKED]
393 // A change in the given field will cause the compiler to completely clear the
394 // incremental compilation cache before proceeding.
395 //
396 // [UNTRACKED]
397 // Incremental compilation is not influenced by this option.
398 //
399 // If you add a new option to this struct or one of the sub-structs like
400 // `CodegenOptions`, think about how it influences incremental compilation. If in
401 // doubt, specify [TRACKED], which is always "correct" but might lead to
402 // unnecessary re-compilation.
403 top_level_options!(
404     pub struct Options {
405         // The crate config requested for the session, which may be combined
406         // with additional crate configurations during the compile process.
407         crate_types: Vec<CrateType> [TRACKED],
408         optimize: OptLevel [TRACKED],
409         // Include the `debug_assertions` flag in dependency tracking, since it
410         // can influence whether overflow checks are done or not.
411         debug_assertions: bool [TRACKED],
412         debuginfo: DebugInfo [TRACKED],
413         lint_opts: Vec<(String, lint::Level)> [TRACKED],
414         lint_cap: Option<lint::Level> [TRACKED],
415         describe_lints: bool [UNTRACKED],
416         output_types: OutputTypes [TRACKED],
417         search_paths: Vec<SearchPath> [UNTRACKED],
418         libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
419         maybe_sysroot: Option<PathBuf> [UNTRACKED],
420
421         target_triple: TargetTriple [TRACKED],
422
423         test: bool [TRACKED],
424         error_format: ErrorOutputType [UNTRACKED],
425
426         // If `Some`, enable incremental compilation, using the given
427         // directory to store intermediate results.
428         incremental: Option<PathBuf> [UNTRACKED],
429
430         debugging_opts: DebuggingOptions [TRACKED],
431         prints: Vec<PrintRequest> [UNTRACKED],
432         // Determines which borrow checker(s) to run. This is the parsed, sanitized
433         // version of `debugging_opts.borrowck`, which is just a plain string.
434         borrowck_mode: BorrowckMode [UNTRACKED],
435         cg: CodegenOptions [TRACKED],
436         externs: Externs [UNTRACKED],
437         crate_name: Option<String> [TRACKED],
438         // An optional name to use as the crate for std during std injection,
439         // written `extern crate name as std`. Defaults to `std`. Used by
440         // out-of-tree drivers.
441         alt_std_name: Option<String> [TRACKED],
442         // Indicates how the compiler should treat unstable features.
443         unstable_features: UnstableFeatures [TRACKED],
444
445         // Indicates whether this run of the compiler is actually rustdoc. This
446         // is currently just a hack and will be removed eventually, so please
447         // try to not rely on this too much.
448         actually_rustdoc: bool [TRACKED],
449
450         // Specifications of codegen units / ThinLTO which are forced as a
451         // result of parsing command line options. These are not necessarily
452         // what rustc was invoked with, but massaged a bit to agree with
453         // commands like `--emit llvm-ir` which they're often incompatible with
454         // if we otherwise use the defaults of rustc.
455         cli_forced_codegen_units: Option<usize> [UNTRACKED],
456         cli_forced_thinlto_off: bool [UNTRACKED],
457
458         // Remap source path prefixes in all output (messages, object files, debug, etc.).
459         remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
460
461         edition: Edition [TRACKED],
462
463         // `true` if we're emitting JSON blobs about each artifact produced
464         // by the compiler.
465         json_artifact_notifications: bool [TRACKED],
466
467         pretty: Option<PpMode> [UNTRACKED],
468     }
469 );
470
471 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
472 pub enum PrintRequest {
473     FileNames,
474     Sysroot,
475     CrateName,
476     Cfg,
477     TargetList,
478     TargetCPUs,
479     TargetFeatures,
480     RelocationModels,
481     CodeModels,
482     TlsModels,
483     TargetSpec,
484     NativeStaticLibs,
485 }
486
487 #[derive(Copy, Clone)]
488 pub enum BorrowckMode {
489     Mir,
490     Migrate,
491 }
492
493 impl BorrowckMode {
494     /// Returns whether we should run the MIR-based borrow check, but also fall back
495     /// on the AST borrow check if the MIR-based one errors.
496     pub fn migrate(self) -> bool {
497         match self {
498             BorrowckMode::Mir => false,
499             BorrowckMode::Migrate => true,
500         }
501     }
502 }
503
504 pub enum Input {
505     /// Load source code from a file.
506     File(PathBuf),
507     /// Load source code from a string.
508     Str {
509         /// A string that is shown in place of a filename.
510         name: FileName,
511         /// An anonymous string containing the source code.
512         input: String,
513     },
514 }
515
516 impl Input {
517     pub fn filestem(&self) -> &str {
518         match *self {
519             Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
520             Input::Str { .. } => "rust_out",
521         }
522     }
523
524     pub fn get_input(&mut self) -> Option<&mut String> {
525         match *self {
526             Input::File(_) => None,
527             Input::Str { ref mut input, .. } => Some(input),
528         }
529     }
530
531     pub fn source_name(&self) -> FileName {
532         match *self {
533             Input::File(ref ifile) => ifile.clone().into(),
534             Input::Str { ref name, .. } => name.clone(),
535         }
536     }
537 }
538
539 #[derive(Clone, Hash)]
540 pub struct OutputFilenames {
541     pub out_directory: PathBuf,
542     pub out_filestem: String,
543     pub single_output_file: Option<PathBuf>,
544     pub extra: String,
545     pub outputs: OutputTypes,
546 }
547
548 impl_stable_hash_via_hash!(OutputFilenames);
549
550 pub const RUST_CGU_EXT: &str = "rcgu";
551
552 impl OutputFilenames {
553     pub fn path(&self, flavor: OutputType) -> PathBuf {
554         self.outputs
555             .get(&flavor)
556             .and_then(|p| p.to_owned())
557             .or_else(|| self.single_output_file.clone())
558             .unwrap_or_else(|| self.temp_path(flavor, None))
559     }
560
561     /// Gets the path where a compilation artifact of the given type for the
562     /// given codegen unit should be placed on disk. If codegen_unit_name is
563     /// None, a path distinct from those of any codegen unit will be generated.
564     pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
565         let extension = flavor.extension();
566         self.temp_path_ext(extension, codegen_unit_name)
567     }
568
569     /// Like temp_path, but also supports things where there is no corresponding
570     /// OutputType, like noopt-bitcode or lto-bitcode.
571     pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
572         let base = self.out_directory.join(&self.filestem());
573
574         let mut extension = String::new();
575
576         if let Some(codegen_unit_name) = codegen_unit_name {
577             extension.push_str(codegen_unit_name);
578         }
579
580         if !ext.is_empty() {
581             if !extension.is_empty() {
582                 extension.push_str(".");
583                 extension.push_str(RUST_CGU_EXT);
584                 extension.push_str(".");
585             }
586
587             extension.push_str(ext);
588         }
589
590         let path = base.with_extension(&extension[..]);
591         path
592     }
593
594     pub fn with_extension(&self, extension: &str) -> PathBuf {
595         self.out_directory
596             .join(&self.filestem())
597             .with_extension(extension)
598     }
599
600     pub fn filestem(&self) -> String {
601         format!("{}{}", self.out_filestem, self.extra)
602     }
603 }
604
605 pub fn host_triple() -> &'static str {
606     // Get the host triple out of the build environment. This ensures that our
607     // idea of the host triple is the same as for the set of libraries we've
608     // actually built.  We can't just take LLVM's host triple because they
609     // normalize all ix86 architectures to i386.
610     //
611     // Instead of grabbing the host triple (for the current host), we grab (at
612     // compile time) the target triple that this rustc is built with and
613     // calling that (at runtime) the host triple.
614     (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
615 }
616
617 impl Default for Options {
618     fn default() -> Options {
619         Options {
620             crate_types: Vec::new(),
621             optimize: OptLevel::No,
622             debuginfo: DebugInfo::None,
623             lint_opts: Vec::new(),
624             lint_cap: None,
625             describe_lints: false,
626             output_types: OutputTypes(BTreeMap::new()),
627             search_paths: vec![],
628             maybe_sysroot: None,
629             target_triple: TargetTriple::from_triple(host_triple()),
630             test: false,
631             incremental: None,
632             debugging_opts: basic_debugging_options(),
633             prints: Vec::new(),
634             borrowck_mode: BorrowckMode::Migrate,
635             cg: basic_codegen_options(),
636             error_format: ErrorOutputType::default(),
637             externs: Externs(BTreeMap::new()),
638             crate_name: None,
639             alt_std_name: None,
640             libs: Vec::new(),
641             unstable_features: UnstableFeatures::Disallow,
642             debug_assertions: true,
643             actually_rustdoc: false,
644             cli_forced_codegen_units: None,
645             cli_forced_thinlto_off: false,
646             remap_path_prefix: Vec::new(),
647             edition: DEFAULT_EDITION,
648             json_artifact_notifications: false,
649             pretty: None,
650         }
651     }
652 }
653
654 impl Options {
655     /// Returns `true` if there is a reason to build the dep graph.
656     pub fn build_dep_graph(&self) -> bool {
657         self.incremental.is_some() || self.debugging_opts.dump_dep_graph
658             || self.debugging_opts.query_dep_graph
659     }
660
661     #[inline(always)]
662     pub fn enable_dep_node_debug_strs(&self) -> bool {
663         cfg!(debug_assertions)
664             && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
665     }
666
667     pub fn file_path_mapping(&self) -> FilePathMapping {
668         FilePathMapping::new(self.remap_path_prefix.clone())
669     }
670
671     /// Returns `true` if there will be an output file generated.
672     pub fn will_create_output_file(&self) -> bool {
673         !self.debugging_opts.parse_only && // The file is just being parsed
674             !self.debugging_opts.ls // The file is just being queried
675     }
676
677     #[inline]
678     pub fn share_generics(&self) -> bool {
679         match self.debugging_opts.share_generics {
680             Some(setting) => setting,
681             None => {
682                 match self.optimize {
683                     OptLevel::No   |
684                     OptLevel::Less |
685                     OptLevel::Size |
686                     OptLevel::SizeMin => true,
687                     OptLevel::Default    |
688                     OptLevel::Aggressive => false,
689                 }
690             }
691         }
692     }
693 }
694
695 // The type of entry function, so users can have their own entry functions
696 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
697 pub enum EntryFnType {
698     Main,
699     Start,
700 }
701
702 impl_stable_hash_via_hash!(EntryFnType);
703
704 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
705 pub enum CrateType {
706     Executable,
707     Dylib,
708     Rlib,
709     Staticlib,
710     Cdylib,
711     ProcMacro,
712 }
713
714 impl_stable_hash_via_hash!(CrateType);
715
716 #[derive(Clone, Hash)]
717 pub enum Passes {
718     Some(Vec<String>),
719     All,
720 }
721
722 impl Passes {
723     pub fn is_empty(&self) -> bool {
724         match *self {
725             Passes::Some(ref v) => v.is_empty(),
726             Passes::All => false,
727         }
728     }
729 }
730
731 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
732 /// macro is to define an interface that can be programmatically used by the option parser
733 /// to initialize the struct without hardcoding field names all over the place.
734 ///
735 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
736 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
737 /// generated code to parse an option into its respective field in the struct. There are a few
738 /// hand-written parsers for parsing specific types of values in this module.
739 macro_rules! options {
740     ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
741      $buildfn:ident, $prefix:expr, $outputname:expr,
742      $stat:ident, $mod_desc:ident, $mod_set:ident,
743      $($opt:ident : $t:ty = (
744         $init:expr,
745         $parse:ident,
746         [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
747         $desc:expr)
748      ),* ,) =>
749 (
750     #[derive(Clone)]
751     pub struct $struct_name { $(pub $opt: $t),* }
752
753     pub fn $defaultfn() -> $struct_name {
754         $struct_name { $($opt: $init),* }
755     }
756
757     pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
758     {
759         let mut op = $defaultfn();
760         for option in matches.opt_strs($prefix) {
761             let mut iter = option.splitn(2, '=');
762             let key = iter.next().unwrap();
763             let value = iter.next();
764             let option_to_lookup = key.replace("-", "_");
765             let mut found = false;
766             for &(candidate, setter, opt_type_desc, _) in $stat {
767                 if option_to_lookup != candidate { continue }
768                 if !setter(&mut op, value) {
769                     match (value, opt_type_desc) {
770                         (Some(..), None) => {
771                             early_error(error_format, &format!("{} option `{}` takes no \
772                                                                 value", $outputname, key))
773                         }
774                         (None, Some(type_desc)) => {
775                             early_error(error_format, &format!("{0} option `{1}` requires \
776                                                                 {2} ({3} {1}=<value>)",
777                                                                $outputname, key,
778                                                                type_desc, $prefix))
779                         }
780                         (Some(value), Some(type_desc)) => {
781                             early_error(error_format, &format!("incorrect value `{}` for {} \
782                                                                 option `{}` - {} was expected",
783                                                                value, $outputname,
784                                                                key, type_desc))
785                         }
786                         (None, None) => panic!()
787                     }
788                 }
789                 found = true;
790                 break;
791             }
792             if !found {
793                 early_error(error_format, &format!("unknown {} option: `{}`",
794                                                    $outputname, key));
795             }
796         }
797         return op;
798     }
799
800     impl dep_tracking::DepTrackingHash for $struct_name {
801         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
802             let mut sub_hashes = BTreeMap::new();
803             $({
804                 hash_option!($opt,
805                              &self.$opt,
806                              &mut sub_hashes,
807                              [$dep_tracking_marker $($dep_warn_val,
808                                                      $dep_warn_text,
809                                                      error_format)*]);
810             })*
811             dep_tracking::stable_hash(sub_hashes, hasher, error_format);
812         }
813     }
814
815     pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
816     pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
817         &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
818
819     #[allow(non_upper_case_globals, dead_code)]
820     mod $mod_desc {
821         pub const parse_bool: Option<&str> = None;
822         pub const parse_opt_bool: Option<&str> =
823             Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
824         pub const parse_string: Option<&str> = Some("a string");
825         pub const parse_string_push: Option<&str> = Some("a string");
826         pub const parse_pathbuf_push: Option<&str> = Some("a path");
827         pub const parse_opt_string: Option<&str> = Some("a string");
828         pub const parse_opt_pathbuf: Option<&str> = Some("a path");
829         pub const parse_list: Option<&str> = Some("a space-separated list of strings");
830         pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
831         pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
832         pub const parse_threads: Option<&str> = Some("a number");
833         pub const parse_uint: Option<&str> = Some("a number");
834         pub const parse_passes: Option<&str> =
835             Some("a space-separated list of passes, or `all`");
836         pub const parse_opt_uint: Option<&str> =
837             Some("a number");
838         pub const parse_panic_strategy: Option<&str> =
839             Some("either `unwind` or `abort`");
840         pub const parse_relro_level: Option<&str> =
841             Some("one of: `full`, `partial`, or `off`");
842         pub const parse_sanitizer: Option<&str> =
843             Some("one of: `address`, `leak`, `memory` or `thread`");
844         pub const parse_sanitizer_list: Option<&str> =
845             Some("comma separated list of sanitizers");
846         pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
847         pub const parse_linker_flavor: Option<&str> =
848             Some(::rustc_target::spec::LinkerFlavor::one_of());
849         pub const parse_optimization_fuel: Option<&str> =
850             Some("crate=integer");
851         pub const parse_unpretty: Option<&str> =
852             Some("`string` or `string=string`");
853         pub const parse_treat_err_as_bug: Option<&str> =
854             Some("either no value or a number bigger than 0");
855         pub const parse_lto: Option<&str> =
856             Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
857                   `fat`, or omitted");
858         pub const parse_linker_plugin_lto: Option<&str> =
859             Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
860                   or the path to the linker plugin");
861         pub const parse_switch_with_opt_path: Option<&str> =
862             Some("an optional path to the profiling data output directory");
863         pub const parse_merge_functions: Option<&str> =
864             Some("one of: `disabled`, `trampolines`, or `aliases`");
865         pub const parse_symbol_mangling_version: Option<&str> =
866             Some("either `legacy` or `v0` (RFC 2603)");
867     }
868
869     #[allow(dead_code)]
870     mod $mod_set {
871         use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
872             SymbolManglingVersion};
873         use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
874         use std::path::PathBuf;
875         use std::str::FromStr;
876
877         $(
878             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
879                 $parse(&mut cg.$opt, v)
880             }
881         )*
882
883         fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
884             match v {
885                 Some(..) => false,
886                 None => { *slot = true; true }
887             }
888         }
889
890         fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
891             match v {
892                 Some(s) => {
893                     match s {
894                         "n" | "no" | "off" => {
895                             *slot = Some(false);
896                         }
897                         "y" | "yes" | "on" => {
898                             *slot = Some(true);
899                         }
900                         _ => { return false; }
901                     }
902
903                     true
904                 },
905                 None => { *slot = Some(true); true }
906             }
907         }
908
909         fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
910             match v {
911                 Some(s) => { *slot = Some(s.to_string()); true },
912                 None => false,
913             }
914         }
915
916         fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
917             match v {
918                 Some(s) => { *slot = Some(PathBuf::from(s)); true },
919                 None => false,
920             }
921         }
922
923         fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
924             match v {
925                 Some(s) => { *slot = s.to_string(); true },
926                 None => false,
927             }
928         }
929
930         fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
931             match v {
932                 Some(s) => { slot.push(s.to_string()); true },
933                 None => false,
934             }
935         }
936
937         fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
938             match v {
939                 Some(s) => { slot.push(PathBuf::from(s)); true },
940                 None => false,
941             }
942         }
943
944         fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
945                       -> bool {
946             match v {
947                 Some(s) => {
948                     slot.extend(s.split_whitespace().map(|s| s.to_string()));
949                     true
950                 },
951                 None => false,
952             }
953         }
954
955         fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
956                       -> bool {
957             match v {
958                 Some(s) => {
959                     let v = s.split_whitespace().map(|s| s.to_string()).collect();
960                     *slot = Some(v);
961                     true
962                 },
963                 None => false,
964             }
965         }
966
967         fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
968                       -> bool {
969             match v {
970                 Some(s) => {
971                     let v = s.split(',').map(|s| s.to_string()).collect();
972                     *slot = Some(v);
973                     true
974                 },
975                 None => false,
976             }
977         }
978
979         fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
980             match v.and_then(|s| s.parse().ok()) {
981                 Some(0) => { *slot = ::num_cpus::get(); true },
982                 Some(i) => { *slot = i; true },
983                 None => false
984             }
985         }
986
987         fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
988             match v.and_then(|s| s.parse().ok()) {
989                 Some(i) => { *slot = i; true },
990                 None => false
991             }
992         }
993
994         fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
995             match v {
996                 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
997                 None => { *slot = None; false }
998             }
999         }
1000
1001         fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
1002             match v {
1003                 Some("all") => {
1004                     *slot = Passes::All;
1005                     true
1006                 }
1007                 v => {
1008                     let mut passes = vec![];
1009                     if parse_list(&mut passes, v) {
1010                         *slot = Passes::Some(passes);
1011                         true
1012                     } else {
1013                         false
1014                     }
1015                 }
1016             }
1017         }
1018
1019         fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
1020             match v {
1021                 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1022                 Some("abort") => *slot = Some(PanicStrategy::Abort),
1023                 _ => return false
1024             }
1025             true
1026         }
1027
1028         fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1029             match v {
1030                 Some(s) => {
1031                     match s.parse::<RelroLevel>() {
1032                         Ok(level) => *slot = Some(level),
1033                         _ => return false
1034                     }
1035                 },
1036                 _ => return false
1037             }
1038             true
1039         }
1040
1041         fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1042             if let Some(Ok(s)) =  v.map(str::parse) {
1043                 *slot = Some(s);
1044                 true
1045             } else {
1046                 false
1047             }
1048         }
1049
1050         fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
1051             if let Some(v) = v {
1052                 for s in v.split(',').map(str::parse) {
1053                     if let Ok(s) = s {
1054                         if !slot.contains(&s) {
1055                             slot.push(s);
1056                         }
1057                     } else {
1058                         return false;
1059                     }
1060                 }
1061                 true
1062             } else {
1063                 false
1064             }
1065         }
1066
1067         fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1068             match v.map(|s| s.parse()) {
1069                 None => {
1070                     *slot = 2;
1071                     true
1072                 }
1073                 Some(Ok(i)) if i <= 2 => {
1074                     *slot = i;
1075                     true
1076                 }
1077                 _ => {
1078                     false
1079                 }
1080             }
1081         }
1082
1083         fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1084             match v.and_then(LinkerFlavor::from_str) {
1085                 Some(lf) => *slote = Some(lf),
1086                 _ => return false,
1087             }
1088             true
1089         }
1090
1091         fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1092             match v {
1093                 None => false,
1094                 Some(s) => {
1095                     let parts = s.split('=').collect::<Vec<_>>();
1096                     if parts.len() != 2 { return false; }
1097                     let crate_name = parts[0].to_string();
1098                     let fuel = parts[1].parse::<u64>();
1099                     if fuel.is_err() { return false; }
1100                     *slot = Some((crate_name, fuel.unwrap()));
1101                     true
1102                 }
1103             }
1104         }
1105
1106         fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1107             match v {
1108                 None => false,
1109                 Some(s) if s.split('=').count() <= 2 => {
1110                     *slot = Some(s.to_string());
1111                     true
1112                 }
1113                 _ => false,
1114             }
1115         }
1116
1117         fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1118             match v {
1119                 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1120                 None => { *slot = Some(1); true }
1121             }
1122         }
1123
1124         fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1125             if v.is_some() {
1126                 let mut bool_arg = None;
1127                 if parse_opt_bool(&mut bool_arg, v) {
1128                     *slot = if bool_arg.unwrap() {
1129                         LtoCli::Yes
1130                     } else {
1131                         LtoCli::No
1132                     };
1133                     return true
1134                 }
1135             }
1136
1137             *slot = match v {
1138                 None => LtoCli::NoParam,
1139                 Some("thin") => LtoCli::Thin,
1140                 Some("fat") => LtoCli::Fat,
1141                 Some(_) => return false,
1142             };
1143             true
1144         }
1145
1146         fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1147             if v.is_some() {
1148                 let mut bool_arg = None;
1149                 if parse_opt_bool(&mut bool_arg, v) {
1150                     *slot = if bool_arg.unwrap() {
1151                         LinkerPluginLto::LinkerPluginAuto
1152                     } else {
1153                         LinkerPluginLto::Disabled
1154                     };
1155                     return true
1156                 }
1157             }
1158
1159             *slot = match v {
1160                 None => LinkerPluginLto::LinkerPluginAuto,
1161                 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1162             };
1163             true
1164         }
1165
1166         fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1167             *slot = match v {
1168                 None => SwitchWithOptPath::Enabled(None),
1169                 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1170             };
1171             true
1172         }
1173
1174         fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1175             match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1176                 Some(mergefunc) => *slot = Some(mergefunc),
1177                 _ => return false,
1178             }
1179             true
1180         }
1181
1182         fn parse_symbol_mangling_version(
1183             slot: &mut SymbolManglingVersion,
1184             v: Option<&str>,
1185         ) -> bool {
1186             *slot = match v {
1187                 Some("legacy") => SymbolManglingVersion::Legacy,
1188                 Some("v0") => SymbolManglingVersion::V0,
1189                 _ => return false,
1190             };
1191             true
1192         }
1193     }
1194 ) }
1195
1196 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1197           build_codegen_options, "C", "codegen",
1198           CG_OPTIONS, cg_type_desc, cgsetters,
1199     ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1200         "this option is deprecated and does nothing"),
1201     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1202         "system linker to link outputs with"),
1203     link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1204         "a single extra argument to append to the linker invocation (can be used several times)"),
1205     link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1206         "extra arguments to append to the linker invocation (space separated)"),
1207     link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1208         "don't let linker strip dead code (turning it on can be used for code coverage)"),
1209     lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1210         "perform LLVM link-time optimizations"),
1211     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1212         "select target processor (`rustc --print target-cpus` for details)"),
1213     target_feature: String = (String::new(), parse_string, [TRACKED],
1214         "target specific attributes. (`rustc --print target-features` for details). \
1215         This feature is unsafe."),
1216     passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1217         "a list of extra LLVM passes to run (space separated)"),
1218     llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1219         "a list of arguments to pass to LLVM (space separated)"),
1220     save_temps: bool = (false, parse_bool, [UNTRACKED],
1221         "save all temporary output files during compilation"),
1222     rpath: bool = (false, parse_bool, [UNTRACKED],
1223         "set rpath values in libs/exes"),
1224     overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1225         "use overflow checks for integer arithmetic"),
1226     no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1227         "don't pre-populate the pass manager with a list of passes"),
1228     no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1229         "don't run the loop vectorization optimization passes"),
1230     no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1231         "don't run LLVM's SLP vectorization pass"),
1232     soft_float: bool = (false, parse_bool, [TRACKED],
1233         "use soft float ABI (*eabihf targets only)"),
1234     prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1235         "prefer dynamic linking to static linking"),
1236     no_integrated_as: bool = (false, parse_bool, [TRACKED],
1237         "use an external assembler rather than LLVM's integrated one"),
1238     no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1239         "disable the use of the redzone"),
1240     relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1241         "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1242     code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1243         "choose the code model to use (`rustc --print code-models` for details)"),
1244     metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1245         "metadata to mangle symbol names with"),
1246     extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1247         "extra data to put in each output filename"),
1248     codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1249         "divide crate into N units to optimize in parallel"),
1250     remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1251         "print remarks for these optimization passes (space separated, or \"all\")"),
1252     no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1253         "the `--no-stack-check` flag is deprecated and does nothing"),
1254     debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1255         "debug info emission level, 0 = no debug info, 1 = line tables only, \
1256          2 = full debug info with variable and type information"),
1257     opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1258         "optimize with possible levels 0-3, s, or z"),
1259     force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1260         "force use of the frame pointers"),
1261     debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1262         "explicitly enable the `cfg(debug_assertions)` directive"),
1263     inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1264         "set the threshold for inlining a function (default: 225)"),
1265     panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1266         [TRACKED], "panic strategy to compile crate with"),
1267     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1268         "enable incremental compilation"),
1269     default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1270         "allow the linker to link its default libraries"),
1271     linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1272                                            "linker flavor"),
1273     linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1274         parse_linker_plugin_lto, [TRACKED],
1275         "generate build artifacts that are compatible with linker-based LTO."),
1276     profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1277         parse_switch_with_opt_path, [TRACKED],
1278         "compile the program with profiling instrumentation"),
1279     profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1280         "use the given `.profdata` file for profile-guided optimization"),
1281 }
1282
1283 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1284           build_debugging_options, "Z", "debugging",
1285           DB_OPTIONS, db_type_desc, dbsetters,
1286     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1287         "the backend to use"),
1288     verbose: bool = (false, parse_bool, [UNTRACKED],
1289         "in general, enable more debug printouts"),
1290     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1291         "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1292     identify_regions: bool = (false, parse_bool, [UNTRACKED],
1293         "make unnamed regions display as '# (where # is some non-ident unique id)"),
1294     borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1295         "select which borrowck is used (`mir` or `migrate`)"),
1296     time_passes: bool = (false, parse_bool, [UNTRACKED],
1297         "measure time of each rustc pass"),
1298     time: bool = (false, parse_bool, [UNTRACKED],
1299         "measure time of rustc processes"),
1300     time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1301         "measure time of each LLVM pass"),
1302     input_stats: bool = (false, parse_bool, [UNTRACKED],
1303         "gather statistics about the input"),
1304     asm_comments: bool = (false, parse_bool, [TRACKED],
1305         "generate comments into the assembly (may change behavior)"),
1306     verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1307         "verify LLVM IR"),
1308     borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1309         "gather borrowck statistics"),
1310     no_landing_pads: bool = (false, parse_bool, [TRACKED],
1311         "omit landing pads for unwinding"),
1312     fewer_names: bool = (false, parse_bool, [TRACKED],
1313         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1314     meta_stats: bool = (false, parse_bool, [UNTRACKED],
1315         "gather metadata statistics"),
1316     print_link_args: bool = (false, parse_bool, [UNTRACKED],
1317         "print the arguments passed to the linker"),
1318     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1319         "prints the LLVM optimization passes being run"),
1320     ast_json: bool = (false, parse_bool, [UNTRACKED],
1321         "print the AST as JSON and halt"),
1322     // We default to 1 here since we want to behave like
1323     // a sequential compiler for now. This'll likely be adjusted
1324     // in the future. Note that -Zthreads=0 is the way to get
1325     // the num_cpus behavior.
1326     threads: usize = (1, parse_threads, [UNTRACKED],
1327         "use a thread pool with N threads"),
1328     ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1329         "print the pre-expansion AST as JSON and halt"),
1330     ls: bool = (false, parse_bool, [UNTRACKED],
1331         "list the symbols defined by a library crate"),
1332     save_analysis: bool = (false, parse_bool, [UNTRACKED],
1333         "write syntax and type analysis (in JSON format) information, in \
1334          addition to normal output"),
1335     print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1336         "prints region inference graph. \
1337          Use with RUST_REGION_GRAPH=help for more info"),
1338     parse_only: bool = (false, parse_bool, [UNTRACKED],
1339         "parse only; do not compile, assemble, or link"),
1340     dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1341         "load proc macros for both target and host, but only link to the target"),
1342     no_codegen: bool = (false, parse_bool, [TRACKED],
1343         "run all passes except codegen; no output"),
1344     treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1345         "treat error number `val` that occurs as bug"),
1346     report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1347         "immediately print bugs registered with `delay_span_bug`"),
1348     external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1349         "show macro backtraces even for non-local macros"),
1350     teach: bool = (false, parse_bool, [TRACKED],
1351         "show extended diagnostic help"),
1352     terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1353         "set the current terminal width"),
1354     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1355         "support compiling tests with panic=abort"),
1356     continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1357         "attempt to recover from parse errors (experimental)"),
1358     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1359         "print tasks that execute and the color their dep node gets (requires debug build)"),
1360     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1361         "enable incremental compilation (experimental)"),
1362     incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1363         "enable incremental compilation support for queries (experimental)"),
1364     incremental_info: bool = (false, parse_bool, [UNTRACKED],
1365         "print high-level information about incremental reuse (or the lack thereof)"),
1366     incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1367         "dump hash information in textual format to stdout"),
1368     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1369         "verify incr. comp. hashes of green query instances"),
1370     incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1371         "ignore spans during ICH computation -- used for testing"),
1372     instrument_mcount: bool = (false, parse_bool, [TRACKED],
1373         "insert function instrument code for mcount-based tracing"),
1374     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1375         "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1376     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1377         "enable queries of the dependency graph for regression testing"),
1378     no_analysis: bool = (false, parse_bool, [UNTRACKED],
1379         "parse and expand the source, but run no analysis"),
1380     unstable_options: bool = (false, parse_bool, [UNTRACKED],
1381         "adds unstable command line options to rustc interface"),
1382     force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1383         "force overflow checks on or off"),
1384     trace_macros: bool = (false, parse_bool, [UNTRACKED],
1385         "for every macro invocation, print its name and arguments"),
1386     debug_macros: bool = (false, parse_bool, [TRACKED],
1387         "emit line numbers debug info inside macros"),
1388     generate_arange_section: bool = (true, parse_bool, [TRACKED],
1389         "generate DWARF address ranges for faster lookups"),
1390     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1391         "don't clear the hygiene data after analysis"),
1392     keep_ast: bool = (false, parse_bool, [UNTRACKED],
1393         "keep the AST after lowering it to HIR"),
1394     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1395         "show spans for compiler debugging (expr|pat|ty)"),
1396     print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1397         "print layout information for each type encountered"),
1398     print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1399         "print the result of the monomorphization collection pass"),
1400     mir_opt_level: usize = (1, parse_uint, [TRACKED],
1401         "set the MIR optimization level (0-3, default: 1)"),
1402     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1403         "emit noalias metadata for mutable references (default: no)"),
1404     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1405         "dump MIR state to file.
1406         `val` is used to select which passes and functions to dump. For example:
1407         `all` matches all passes and functions,
1408         `foo` matches all passes for functions whose name contains 'foo',
1409         `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1410         `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1411
1412     dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1413         "the directory the MIR is dumped into"),
1414     dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1415         "in addition to `.mir` files, create graphviz `.dot` files"),
1416     dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1417         "if set, exclude the pass number when dumping MIR (used in tests)"),
1418     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1419         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1420     perf_stats: bool = (false, parse_bool, [UNTRACKED],
1421         "print some performance-related statistics"),
1422     query_stats: bool = (false, parse_bool, [UNTRACKED],
1423         "print some statistics about the query system"),
1424     hir_stats: bool = (false, parse_bool, [UNTRACKED],
1425         "print some statistics about AST and HIR"),
1426     always_encode_mir: bool = (false, parse_bool, [TRACKED],
1427         "encode MIR of all functions into the crate metadata"),
1428     json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1429         "describes how to render the `rendered` field of json diagnostics"),
1430     unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1431         "take the breaks off const evaluation. NOTE: this is unsound"),
1432     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1433         "pass `-install_name @rpath/...` to the macOS linker"),
1434     sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1435                                     "use a sanitizer"),
1436     sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
1437         "Enable recovery for selected sanitizers"),
1438     sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
1439         "Enable origins tracking in MemorySanitizer"),
1440     fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1441         "set the optimization fuel quota for a crate"),
1442     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1443         "make rustc print the total optimization fuel used by a crate"),
1444     force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1445         "force all crates to be `rustc_private` unstable"),
1446     pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1447         "a single extra argument to prepend the linker invocation (can be used several times)"),
1448     pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1449         "extra arguments to prepend to the linker invocation (space separated)"),
1450     profile: bool = (false, parse_bool, [TRACKED],
1451                      "insert profiling code"),
1452     disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1453         "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1454     relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1455         "choose which RELRO level to use"),
1456     nll_facts: bool = (false, parse_bool, [UNTRACKED],
1457                        "dump facts from NLL analysis into side files"),
1458     nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1459         "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1460     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1461         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1462     polonius: bool = (false, parse_bool, [UNTRACKED],
1463         "enable polonius-based borrow-checker"),
1464     codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1465         "generate a graphical HTML report of time spent in codegen and LLVM"),
1466     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1467         "enable ThinLTO when possible"),
1468     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1469         "control whether `#[inline]` functions are in all CGUs"),
1470     tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1471         "choose the TLS model to use (`rustc --print tls-models` for details)"),
1472     saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1473         "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1474          the max/min integer respectively, and NaN is mapped to 0"),
1475     human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1476         "generate human-readable, predictable names for codegen units"),
1477     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1478         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1479          themselves"),
1480     unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1481         "present the input source, unstable (and less-pretty) variants;
1482         valid types are any of the types for `--pretty`, as well as:
1483         `expanded`, `expanded,identified`,
1484         `expanded,hygiene` (with internal representations),
1485         `everybody_loops` (all function bodies replaced with `loop {}`),
1486         `hir` (the HIR), `hir,identified`,
1487         `hir,typed` (HIR with types for each node),
1488         `hir-tree` (dump the raw HIR),
1489         `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1490     run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1491         "run `dsymutil` and delete intermediate object files"),
1492     ui_testing: bool = (false, parse_bool, [UNTRACKED],
1493         "format compiler diagnostics in a way that's better suitable for UI testing"),
1494     embed_bitcode: bool = (false, parse_bool, [TRACKED],
1495         "embed LLVM bitcode in object files"),
1496     strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1497         "tell the linker to strip debuginfo when building without debuginfo enabled."),
1498     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1499         "make the current crate share its generic instantiations"),
1500     chalk: bool = (false, parse_bool, [TRACKED],
1501         "enable the experimental Chalk-based trait solving engine"),
1502     no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1503         "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1504     no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1505         "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1506     no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1507         "don't interleave execution of lints; allows benchmarking individual lints"),
1508     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1509         "inject the given attribute in the crate"),
1510     self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1511         parse_switch_with_opt_path, [UNTRACKED],
1512         "run the self profiler and output the raw event data"),
1513     self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1514         "specifies which kinds of events get recorded by the self profiler"),
1515     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1516         "emits a section containing stack size metadata"),
1517     plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1518           "whether to use the PLT when calling into shared libraries;
1519           only has effect for PIC code on systems with ELF binaries
1520           (default: PLT is disabled if full relro is enabled)"),
1521     merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1522         "control the operation of the MergeFunctions LLVM pass, taking
1523          the same values as the target option of the same name"),
1524     allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1525         "only allow the listed language features to be enabled in code (space separated)"),
1526     symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1527         parse_symbol_mangling_version, [TRACKED],
1528         "which mangling version to use for symbol names"),
1529     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1530         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1531     insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1532         "fix undefined behavior when a thread doesn't eventually make progress \
1533          (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1534 }
1535
1536 pub const fn default_lib_output() -> CrateType {
1537     CrateType::Rlib
1538 }
1539
1540 pub fn default_configuration(sess: &Session) -> CrateConfig {
1541     let end = &sess.target.target.target_endian;
1542     let arch = &sess.target.target.arch;
1543     let wordsz = &sess.target.target.target_pointer_width;
1544     let os = &sess.target.target.target_os;
1545     let env = &sess.target.target.target_env;
1546     let vendor = &sess.target.target.target_vendor;
1547     let min_atomic_width = sess.target.target.min_atomic_width();
1548     let max_atomic_width = sess.target.target.max_atomic_width();
1549     let atomic_cas = sess.target.target.options.atomic_cas;
1550
1551     let mut ret = FxHashSet::default();
1552     ret.reserve(6); // the minimum number of insertions
1553     // Target bindings.
1554     ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1555     if let Some(ref fam) = sess.target.target.options.target_family {
1556         ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1557         if fam == "windows" || fam == "unix" {
1558             ret.insert((Symbol::intern(fam), None));
1559         }
1560     }
1561     ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1562     ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1563     ret.insert((
1564         Symbol::intern("target_pointer_width"),
1565         Some(Symbol::intern(wordsz)),
1566     ));
1567     ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1568     ret.insert((
1569         Symbol::intern("target_vendor"),
1570         Some(Symbol::intern(vendor)),
1571     ));
1572     if sess.target.target.options.has_elf_tls {
1573         ret.insert((sym::target_thread_local, None));
1574     }
1575     for &i in &[8, 16, 32, 64, 128] {
1576         if i >= min_atomic_width && i <= max_atomic_width {
1577             let mut insert_atomic = |s| {
1578                 ret.insert((
1579                     sym::target_has_atomic_load_store,
1580                     Some(Symbol::intern(s)),
1581                 ));
1582                 if atomic_cas {
1583                     ret.insert((
1584                         sym::target_has_atomic,
1585                         Some(Symbol::intern(s))
1586                     ));
1587                 }
1588             };
1589             let s = i.to_string();
1590             insert_atomic(&s);
1591             if &s == wordsz {
1592               insert_atomic("ptr");
1593             }
1594         }
1595     }
1596     if let Some(s) = &sess.opts.debugging_opts.sanitizer {
1597         let symbol = Symbol::intern(&s.to_string());
1598         ret.insert((sym::sanitize, Some(symbol)));
1599     }
1600     if sess.opts.debug_assertions {
1601         ret.insert((Symbol::intern("debug_assertions"), None));
1602     }
1603     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1604         ret.insert((sym::proc_macro, None));
1605     }
1606     ret
1607 }
1608
1609 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1610 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1611 /// but the symbol interner is not yet set up then, so we must convert it later.
1612 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1613     cfg.into_iter()
1614        .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1615        .collect()
1616 }
1617
1618 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1619     // Combine the configuration requested by the session (command line) with
1620     // some default and generated configuration items.
1621     let default_cfg = default_configuration(sess);
1622     // If the user wants a test runner, then add the test cfg.
1623     if sess.opts.test {
1624         user_cfg.insert((sym::test, None));
1625     }
1626     user_cfg.extend(default_cfg.iter().cloned());
1627     user_cfg
1628 }
1629
1630 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1631     let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1632         sp.struct_fatal(&format!("Error loading target specification: {}", e))
1633           .help("Use `--print target-list` for a list of built-in targets")
1634           .emit();
1635         FatalError.raise();
1636     });
1637
1638     let ptr_width = match &target.target_pointer_width[..] {
1639         "16" => 16,
1640         "32" => 32,
1641         "64" => 64,
1642         w => sp.fatal(&format!(
1643             "target specification was invalid: \
1644              unrecognized target-pointer-width {}",
1645             w
1646         )).raise(),
1647     };
1648
1649     Config {
1650         target,
1651         ptr_width,
1652     }
1653 }
1654
1655 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1656 pub enum OptionStability {
1657     Stable,
1658     Unstable,
1659 }
1660
1661 pub struct RustcOptGroup {
1662     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1663     pub name: &'static str,
1664     pub stability: OptionStability,
1665 }
1666
1667 impl RustcOptGroup {
1668     pub fn is_stable(&self) -> bool {
1669         self.stability == OptionStability::Stable
1670     }
1671
1672     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1673     where
1674         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1675     {
1676         RustcOptGroup {
1677             name,
1678             apply: Box::new(f),
1679             stability: OptionStability::Stable,
1680         }
1681     }
1682
1683     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1684     where
1685         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1686     {
1687         RustcOptGroup {
1688             name,
1689             apply: Box::new(f),
1690             stability: OptionStability::Unstable,
1691         }
1692     }
1693 }
1694
1695 // The `opt` local module holds wrappers around the `getopts` API that
1696 // adds extra rustc-specific metadata to each option; such metadata
1697 // is exposed by .  The public
1698 // functions below ending with `_u` are the functions that return
1699 // *unstable* options, i.e., options that are only enabled when the
1700 // user also passes the `-Z unstable-options` debugging flag.
1701 mod opt {
1702     // The `fn flag*` etc below are written so that we can use them
1703     // in the future; do not warn about them not being used right now.
1704     #![allow(dead_code)]
1705
1706     use getopts;
1707     use super::RustcOptGroup;
1708
1709     pub type R = RustcOptGroup;
1710     pub type S = &'static str;
1711
1712     fn stable<F>(name: S, f: F) -> R
1713     where
1714         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1715     {
1716         RustcOptGroup::stable(name, f)
1717     }
1718
1719     fn unstable<F>(name: S, f: F) -> R
1720     where
1721         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1722     {
1723         RustcOptGroup::unstable(name, f)
1724     }
1725
1726     fn longer(a: S, b: S) -> S {
1727         if a.len() > b.len() {
1728             a
1729         } else {
1730             b
1731         }
1732     }
1733
1734     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1735         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1736     }
1737     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1738         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1739     }
1740     pub fn flag_s(a: S, b: S, c: S) -> R {
1741         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1742     }
1743     pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1744         stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1745     }
1746     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1747         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1748     }
1749
1750     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1751         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1752     }
1753     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1754         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1755     }
1756     pub fn flag(a: S, b: S, c: S) -> R {
1757         unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1758     }
1759     pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1760         unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1761     }
1762     pub fn flagmulti(a: S, b: S, c: S) -> R {
1763         unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1764     }
1765 }
1766
1767 /// Returns the "short" subset of the rustc command line options,
1768 /// including metadata for each option, such as whether the option is
1769 /// part of the stable long-term interface for rustc.
1770 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1771     vec![
1772         opt::flag_s("h", "help", "Display this message"),
1773         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1774         opt::multi_s(
1775             "L",
1776             "",
1777             "Add a directory to the library search path. The
1778                              optional KIND can be one of dependency, crate, native,
1779                              framework, or all (the default).",
1780             "[KIND=]PATH",
1781         ),
1782         opt::multi_s(
1783             "l",
1784             "",
1785             "Link the generated crate(s) to the specified native
1786                              library NAME. The optional KIND can be one of
1787                              static, framework, or dylib (the default).",
1788             "[KIND=]NAME",
1789         ),
1790         make_crate_type_option(),
1791         opt::opt_s(
1792             "",
1793             "crate-name",
1794             "Specify the name of the crate being built",
1795             "NAME",
1796         ),
1797         opt::opt_s(
1798             "",
1799             "edition",
1800             "Specify which edition of the compiler to use when compiling code.",
1801             EDITION_NAME_LIST,
1802         ),
1803         opt::multi_s(
1804             "",
1805             "emit",
1806             "Comma separated list of types of output for \
1807              the compiler to emit",
1808             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1809         ),
1810         opt::multi_s(
1811             "",
1812             "print",
1813             "Compiler information to print on stdout",
1814             "[crate-name|file-names|sysroot|cfg|target-list|\
1815              target-cpus|target-features|relocation-models|\
1816              code-models|tls-models|target-spec-json|native-static-libs]",
1817         ),
1818         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1819         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1820         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1821         opt::opt_s(
1822             "",
1823             "out-dir",
1824             "Write output to compiler-chosen filename \
1825              in <dir>",
1826             "DIR",
1827         ),
1828         opt::opt_s(
1829             "",
1830             "explain",
1831             "Provide a detailed explanation of an error \
1832              message",
1833             "OPT",
1834         ),
1835         opt::flag_s("", "test", "Build a test harness"),
1836         opt::opt_s(
1837             "",
1838             "target",
1839             "Target triple for which the code is compiled",
1840             "TARGET",
1841         ),
1842         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1843         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1844         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1845         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1846         opt::multi_s(
1847             "",
1848             "cap-lints",
1849             "Set the most restrictive lint level. \
1850              More restrictive lints are capped at this \
1851              level",
1852             "LEVEL",
1853         ),
1854         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1855         opt::flag_s("V", "version", "Print version info and exit"),
1856         opt::flag_s("v", "verbose", "Use verbose output"),
1857     ]
1858 }
1859
1860 /// Returns all rustc command line options, including metadata for
1861 /// each option, such as whether the option is part of the stable
1862 /// long-term interface for rustc.
1863 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1864     let mut opts = rustc_short_optgroups();
1865     opts.extend(vec![
1866         opt::multi_s(
1867             "",
1868             "extern",
1869             "Specify where an external rust library is located",
1870             "NAME[=PATH]",
1871         ),
1872         opt::multi_s(
1873             "",
1874             "extern-private",
1875             "Specify where an extern rust library is located, marking it as a private dependency",
1876             "NAME=PATH",
1877         ),
1878         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1879         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1880         opt::opt_s(
1881             "",
1882             "error-format",
1883             "How errors and other messages are produced",
1884             "human|json|short",
1885         ),
1886         opt::multi_s(
1887             "",
1888             "json",
1889             "Configure the JSON output of the compiler",
1890             "CONFIG",
1891         ),
1892         opt::opt_s(
1893             "",
1894             "color",
1895             "Configure coloring of output:
1896                                  auto   = colorize, if output goes to a tty (default);
1897                                  always = always colorize output;
1898                                  never  = never colorize output",
1899             "auto|always|never",
1900         ),
1901         opt::opt(
1902             "",
1903             "pretty",
1904             "Pretty-print the input instead of compiling;
1905                   valid types are: `normal` (un-annotated source),
1906                   `expanded` (crates expanded), or
1907                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1908             "TYPE",
1909         ),
1910         opt::multi_s(
1911             "",
1912             "remap-path-prefix",
1913             "Remap source names in all output (compiler messages and output files)",
1914             "FROM=TO",
1915         ),
1916     ]);
1917     opts
1918 }
1919
1920 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1921                             error_format: ErrorOutputType)
1922                             -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1923     let mut lint_opts = vec![];
1924     let mut describe_lints = false;
1925
1926     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1927         for lint_name in matches.opt_strs(level.as_str()) {
1928             if lint_name == "help" {
1929                 describe_lints = true;
1930             } else {
1931                 lint_opts.push((lint_name.replace("-", "_"), level));
1932             }
1933         }
1934     }
1935
1936     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1937         lint::Level::from_str(&cap)
1938             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1939     });
1940     (lint_opts, describe_lints, lint_cap)
1941 }
1942
1943 /// Parses the `--color` flag.
1944 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1945     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1946         Some("auto") => ColorConfig::Auto,
1947         Some("always") => ColorConfig::Always,
1948         Some("never") => ColorConfig::Never,
1949
1950         None => ColorConfig::Auto,
1951
1952         Some(arg) => early_error(
1953             ErrorOutputType::default(),
1954             &format!(
1955                 "argument for `--color` must be auto, \
1956                  always or never (instead was `{}`)",
1957                 arg
1958             ),
1959         ),
1960     }
1961 }
1962
1963 /// Parse the `--json` flag.
1964 ///
1965 /// The first value returned is how to render JSON diagnostics, and the second
1966 /// is whether or not artifact notifications are enabled.
1967 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1968     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1969         HumanReadableErrorType::Default;
1970     let mut json_color = ColorConfig::Never;
1971     let mut json_artifact_notifications = false;
1972     for option in matches.opt_strs("json") {
1973         // For now conservatively forbid `--color` with `--json` since `--json`
1974         // won't actually be emitting any colors and anything colorized is
1975         // embedded in a diagnostic message anyway.
1976         if matches.opt_str("color").is_some() {
1977             early_error(
1978                 ErrorOutputType::default(),
1979                 "cannot specify the `--color` option with `--json`",
1980             );
1981         }
1982
1983         for sub_option in option.split(',') {
1984             match sub_option {
1985                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1986                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1987                 "artifacts" => json_artifact_notifications = true,
1988                 s => {
1989                     early_error(
1990                         ErrorOutputType::default(),
1991                         &format!("unknown `--json` option `{}`", s),
1992                     )
1993                 }
1994             }
1995         }
1996     }
1997     (json_rendered(json_color), json_artifact_notifications)
1998 }
1999
2000 /// Parses the `--error-format` flag.
2001 pub fn parse_error_format(
2002     matches: &getopts::Matches,
2003     color: ColorConfig,
2004     json_rendered: HumanReadableErrorType,
2005 ) -> ErrorOutputType {
2006     // We need the `opts_present` check because the driver will send us Matches
2007     // with only stable options if no unstable options are used. Since error-format
2008     // is unstable, it will not be present. We have to use `opts_present` not
2009     // `opt_present` because the latter will panic.
2010     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2011         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
2012             None |
2013             Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2014             Some("human-annotate-rs") => {
2015                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
2016             },
2017             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
2018             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
2019             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2020
2021             Some(arg) => early_error(
2022                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2023                 &format!(
2024                     "argument for `--error-format` must be `human`, `json` or \
2025                      `short` (instead was `{}`)",
2026                     arg
2027                 ),
2028             ),
2029         }
2030     } else {
2031         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2032     };
2033
2034     match error_format {
2035         ErrorOutputType::Json { .. } => {}
2036
2037         // Conservatively require that the `--json` argument is coupled with
2038         // `--error-format=json`. This means that `--json` is specified we
2039         // should actually be emitting JSON blobs.
2040         _ if matches.opt_strs("json").len() > 0 => {
2041             early_error(
2042                 ErrorOutputType::default(),
2043                 "using `--json` requires also using `--error-format=json`",
2044             );
2045         }
2046
2047         _ => {}
2048     }
2049
2050     return error_format;
2051 }
2052
2053 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
2054     let edition = match matches.opt_str("edition") {
2055         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2056             early_error(
2057                 ErrorOutputType::default(),
2058                 &format!(
2059                     "argument for `--edition` must be one of: \
2060                      {}. (instead was `{}`)",
2061                     EDITION_NAME_LIST,
2062                     arg
2063                 ),
2064             ),
2065         ),
2066         None => DEFAULT_EDITION,
2067     };
2068
2069     if !edition.is_stable() && !nightly_options::is_nightly_build() {
2070         early_error(
2071                 ErrorOutputType::default(),
2072                 &format!(
2073                     "edition {} is unstable and only \
2074                      available for nightly builds of rustc.",
2075                     edition,
2076                 )
2077         )
2078     }
2079
2080     edition
2081 }
2082
2083 fn check_debug_option_stability(
2084     debugging_opts: &DebuggingOptions,
2085     error_format: ErrorOutputType,
2086     json_rendered: HumanReadableErrorType,
2087 ) {
2088     if !debugging_opts.unstable_options {
2089         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2090             early_error(
2091                 ErrorOutputType::Json { pretty: false, json_rendered },
2092                 "`--error-format=pretty-json` is unstable",
2093             );
2094         }
2095         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2096             error_format {
2097             early_error(
2098                 ErrorOutputType::Json { pretty: false, json_rendered },
2099                 "`--error-format=human-annotate-rs` is unstable",
2100             );
2101         }
2102     }
2103 }
2104
2105 fn parse_output_types(
2106     debugging_opts: &DebuggingOptions,
2107     matches: &getopts::Matches,
2108     error_format: ErrorOutputType,
2109 ) -> OutputTypes {
2110     let mut output_types = BTreeMap::new();
2111     if !debugging_opts.parse_only {
2112         for list in matches.opt_strs("emit") {
2113             for output_type in list.split(',') {
2114                 let mut parts = output_type.splitn(2, '=');
2115                 let shorthand = parts.next().unwrap();
2116                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2117                     early_error(
2118                         error_format,
2119                         &format!(
2120                             "unknown emission type: `{}` - expected one of: {}",
2121                             shorthand,
2122                             OutputType::shorthands_display(),
2123                         ),
2124                     ),
2125                 );
2126                 let path = parts.next().map(PathBuf::from);
2127                 output_types.insert(output_type, path);
2128             }
2129         }
2130     };
2131     if output_types.is_empty() {
2132         output_types.insert(OutputType::Exe, None);
2133     }
2134     OutputTypes(output_types)
2135 }
2136
2137 fn should_override_cgus_and_disable_thinlto(
2138     output_types: &OutputTypes,
2139     matches: &getopts::Matches,
2140     error_format: ErrorOutputType,
2141     mut codegen_units: Option<usize>,
2142 ) -> (bool, Option<usize>) {
2143     let mut disable_thinlto = false;
2144     // Issue #30063: if user requests LLVM-related output to one
2145     // particular path, disable codegen-units.
2146     let incompatible: Vec<_> = output_types.0
2147         .iter()
2148         .map(|ot_path| ot_path.0)
2149         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2150         .map(|ot| ot.shorthand())
2151         .collect();
2152     if !incompatible.is_empty() {
2153         match codegen_units {
2154             Some(n) if n > 1 => {
2155                 if matches.opt_present("o") {
2156                     for ot in &incompatible {
2157                         early_warn(
2158                             error_format,
2159                             &format!(
2160                                 "`--emit={}` with `-o` incompatible with \
2161                                  `-C codegen-units=N` for N > 1",
2162                                 ot
2163                             ),
2164                         );
2165                     }
2166                     early_warn(error_format, "resetting to default -C codegen-units=1");
2167                     codegen_units = Some(1);
2168                     disable_thinlto = true;
2169                 }
2170             }
2171             _ => {
2172                 codegen_units = Some(1);
2173                 disable_thinlto = true;
2174             }
2175         }
2176     }
2177
2178     if codegen_units == Some(0) {
2179         early_error(
2180             error_format,
2181             "value for codegen units must be a positive non-zero integer",
2182         );
2183     }
2184
2185     (disable_thinlto, codegen_units)
2186 }
2187
2188 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2189     if debugging_opts.threads == 0 {
2190         early_error(
2191             error_format,
2192             "value for threads must be a positive non-zero integer",
2193         );
2194     }
2195
2196     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2197         early_error(
2198             error_format,
2199             "optimization fuel is incompatible with multiple threads",
2200         );
2201     }
2202 }
2203
2204 fn select_incremental_path(
2205     debugging_opts: &DebuggingOptions,
2206     cg: &CodegenOptions,
2207     error_format: ErrorOutputType,
2208 ) -> Option<PathBuf> {
2209     match (&debugging_opts.incremental, &cg.incremental) {
2210         (Some(path1), Some(path2)) => {
2211             if path1 != path2 {
2212                 early_error(
2213                     error_format,
2214                     &format!(
2215                         "conflicting paths for `-Z incremental` and \
2216                          `-C incremental` specified: {} versus {}",
2217                         path1, path2
2218                     ),
2219                 );
2220             } else {
2221                 Some(path1)
2222             }
2223         }
2224         (Some(path), None) => Some(path),
2225         (None, Some(path)) => Some(path),
2226         (None, None) => None,
2227     }.map(|m| PathBuf::from(m))
2228 }
2229
2230 fn collect_print_requests(
2231     cg: &mut CodegenOptions,
2232     dopts: &mut DebuggingOptions,
2233     matches: &getopts::Matches,
2234     error_format: ErrorOutputType,
2235 ) -> Vec<PrintRequest> {
2236     let mut prints = Vec::<PrintRequest>::new();
2237     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2238         prints.push(PrintRequest::TargetCPUs);
2239         cg.target_cpu = None;
2240     };
2241     if cg.target_feature == "help" {
2242         prints.push(PrintRequest::TargetFeatures);
2243         cg.target_feature = String::new();
2244     }
2245     if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2246         prints.push(PrintRequest::RelocationModels);
2247         cg.relocation_model = None;
2248     }
2249     if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2250         prints.push(PrintRequest::CodeModels);
2251         cg.code_model = None;
2252     }
2253     if dopts
2254         .tls_model
2255         .as_ref()
2256         .map_or(false, |s| s == "help")
2257     {
2258         prints.push(PrintRequest::TlsModels);
2259         dopts.tls_model = None;
2260     }
2261
2262     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2263         "crate-name" => PrintRequest::CrateName,
2264         "file-names" => PrintRequest::FileNames,
2265         "sysroot" => PrintRequest::Sysroot,
2266         "cfg" => PrintRequest::Cfg,
2267         "target-list" => PrintRequest::TargetList,
2268         "target-cpus" => PrintRequest::TargetCPUs,
2269         "target-features" => PrintRequest::TargetFeatures,
2270         "relocation-models" => PrintRequest::RelocationModels,
2271         "code-models" => PrintRequest::CodeModels,
2272         "tls-models" => PrintRequest::TlsModels,
2273         "native-static-libs" => PrintRequest::NativeStaticLibs,
2274         "target-spec-json" => {
2275             if dopts.unstable_options {
2276                 PrintRequest::TargetSpec
2277             } else {
2278                 early_error(
2279                     error_format,
2280                     "the `-Z unstable-options` flag must also be passed to \
2281                      enable the target-spec-json print option",
2282                 );
2283             }
2284         }
2285         req => early_error(error_format, &format!("unknown print request `{}`", req)),
2286     }));
2287
2288     prints
2289 }
2290
2291 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2292     match matches.opt_str("target") {
2293         Some(target) if target.ends_with(".json") => {
2294             let path = Path::new(&target);
2295             TargetTriple::from_path(&path).unwrap_or_else(|_|
2296                 early_error(error_format, &format!("target file {:?} does not exist", path)))
2297         }
2298         Some(target) => TargetTriple::TargetTriple(target),
2299         _ => TargetTriple::from_triple(host_triple()),
2300     }
2301 }
2302
2303 fn parse_opt_level(
2304     matches: &getopts::Matches,
2305     cg: &CodegenOptions,
2306     error_format: ErrorOutputType,
2307 ) -> OptLevel {
2308     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2309     // to use them interchangeably. However, because they're technically different flags,
2310     // we need to work out manually which should take precedence if both are supplied (i.e.
2311     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2312     // comparing them. Note that if a flag is not found, its position will be `None`, which
2313     // always compared less than `Some(_)`.
2314     let max_o = matches.opt_positions("O").into_iter().max();
2315     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2316         if let Some("opt-level") = s.splitn(2, '=').next() {
2317             Some(i)
2318         } else {
2319             None
2320         }
2321     }).max();
2322     if max_o > max_c {
2323         OptLevel::Default
2324     } else {
2325         match cg.opt_level.as_ref().map(String::as_ref) {
2326             None => OptLevel::No,
2327             Some("0") => OptLevel::No,
2328             Some("1") => OptLevel::Less,
2329             Some("2") => OptLevel::Default,
2330             Some("3") => OptLevel::Aggressive,
2331             Some("s") => OptLevel::Size,
2332             Some("z") => OptLevel::SizeMin,
2333             Some(arg) => {
2334                 early_error(
2335                     error_format,
2336                     &format!(
2337                         "optimization level needs to be \
2338                             between 0-3, s or z (instead was `{}`)",
2339                         arg
2340                     ),
2341                 );
2342             }
2343         }
2344     }
2345 }
2346
2347 fn select_debuginfo(
2348     matches: &getopts::Matches,
2349     cg: &CodegenOptions,
2350     error_format: ErrorOutputType,
2351 ) -> DebugInfo {
2352     let max_g = matches.opt_positions("g").into_iter().max();
2353     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2354         if let Some("debuginfo") = s.splitn(2, '=').next() {
2355             Some(i)
2356         } else {
2357             None
2358         }
2359     }).max();
2360     if max_g > max_c {
2361         DebugInfo::Full
2362     } else {
2363         match cg.debuginfo {
2364             None | Some(0) => DebugInfo::None,
2365             Some(1) => DebugInfo::Limited,
2366             Some(2) => DebugInfo::Full,
2367             Some(arg) => {
2368                 early_error(
2369                     error_format,
2370                     &format!(
2371                         "debug info level needs to be between \
2372                          0-2 (instead was `{}`)",
2373                         arg
2374                     ),
2375                 );
2376             }
2377         }
2378     }
2379 }
2380
2381 fn parse_libs(
2382     matches: &getopts::Matches,
2383     error_format: ErrorOutputType,
2384 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
2385     matches
2386         .opt_strs("l")
2387         .into_iter()
2388         .map(|s| {
2389             // Parse string of the form "[KIND=]lib[:new_name]",
2390             // where KIND is one of "dylib", "framework", "static".
2391             let mut parts = s.splitn(2, '=');
2392             let kind = parts.next().unwrap();
2393             let (name, kind) = match (parts.next(), kind) {
2394                 (None, name) => (name, None),
2395                 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
2396                 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
2397                 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
2398                 (Some(name), "static-nobundle") => {
2399                     (name, Some(NativeLibraryKind::NativeStaticNobundle))
2400                 }
2401                 (_, s) => {
2402                     early_error(
2403                         error_format,
2404                         &format!(
2405                             "unknown library kind `{}`, expected \
2406                              one of dylib, framework, or static",
2407                             s
2408                         ),
2409                     );
2410                 }
2411             };
2412             if kind == Some(NativeLibraryKind::NativeStaticNobundle) &&
2413                 !nightly_options::is_nightly_build() {
2414                 early_error(
2415                     error_format,
2416                     &format!(
2417                         "the library kind 'static-nobundle' is only \
2418                          accepted on the nightly compiler"
2419                     ),
2420                 );
2421             }
2422             let mut name_parts = name.splitn(2, ':');
2423             let name = name_parts.next().unwrap();
2424             let new_name = name_parts.next();
2425             (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2426         })
2427         .collect()
2428 }
2429
2430 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2431     match dopts.borrowck.as_ref().map(|s| &s[..]) {
2432         None | Some("migrate") => BorrowckMode::Migrate,
2433         Some("mir") => BorrowckMode::Mir,
2434         Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2435     }
2436 }
2437
2438 fn parse_externs(
2439     matches: &getopts::Matches,
2440     debugging_opts: &DebuggingOptions,
2441     error_format: ErrorOutputType,
2442 ) -> Externs {
2443     if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2444         early_error(
2445             ErrorOutputType::default(),
2446             "'--extern-private' is unstable and only \
2447             available for nightly builds of rustc."
2448         )
2449     }
2450
2451     // We start out with a `Vec<(Option<String>, bool)>>`,
2452     // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2453     // This allows to modify entries in-place to set their correct
2454     // 'public' value.
2455     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2456     for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2457         .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2458
2459         let mut parts = arg.splitn(2, '=');
2460         let name = parts.next().unwrap_or_else(||
2461             early_error(error_format, "--extern value must not be empty"));
2462         let location = parts.next().map(|s| s.to_string());
2463
2464         let entry = externs
2465             .entry(name.to_owned())
2466             .or_default();
2467
2468
2469         entry.locations.insert(location.clone());
2470
2471         // Crates start out being not private,
2472         // and go to being private if we see an '--extern-private'
2473         // flag
2474         entry.is_private_dep |= private;
2475     }
2476     Externs(externs)
2477 }
2478
2479 fn parse_remap_path_prefix(
2480     matches: &getopts::Matches,
2481     error_format: ErrorOutputType
2482 ) -> Vec<(PathBuf, PathBuf)> {
2483     matches
2484         .opt_strs("remap-path-prefix")
2485         .into_iter()
2486         .map(|remap| {
2487             let mut parts = remap.rsplitn(2, '='); // reverse iterator
2488             let to = parts.next();
2489             let from = parts.next();
2490             match (from, to) {
2491                 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2492                 _ => early_error(
2493                     error_format,
2494                     "--remap-path-prefix must contain '=' between FROM and TO",
2495                 ),
2496             }
2497         })
2498         .collect()
2499 }
2500
2501 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2502     let color = parse_color(matches);
2503
2504     let edition = parse_crate_edition(matches);
2505
2506     let (json_rendered, json_artifact_notifications) = parse_json(matches);
2507
2508     let error_format = parse_error_format(matches, color, json_rendered);
2509
2510     let unparsed_crate_types = matches.opt_strs("crate-type");
2511     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2512         .unwrap_or_else(|e| early_error(error_format, &e[..]));
2513
2514     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2515
2516     let mut debugging_opts = build_debugging_options(matches, error_format);
2517     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2518
2519     let output_types = parse_output_types(&debugging_opts, matches, error_format);
2520
2521     let mut cg = build_codegen_options(matches, error_format);
2522     let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2523         &output_types,
2524         matches,
2525         error_format,
2526         cg.codegen_units,
2527     );
2528
2529     check_thread_count(&debugging_opts, error_format);
2530
2531     let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2532
2533     if debugging_opts.profile && incremental.is_some() {
2534         early_error(
2535             error_format,
2536             "can't instrument with gcov profiling when compiling incrementally",
2537         );
2538     }
2539
2540     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2541         early_error(
2542             error_format,
2543             "options `-C profile-generate` and `-C profile-use` are exclusive",
2544         );
2545     }
2546
2547     let prints = collect_print_requests(
2548         &mut cg,
2549         &mut debugging_opts,
2550         matches,
2551         error_format,
2552     );
2553
2554     let cg = cg;
2555
2556     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2557     let target_triple = parse_target_triple(matches, error_format);
2558     let opt_level = parse_opt_level(matches, &cg, error_format);
2559     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2560     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2561     // for more details.
2562     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2563     let debuginfo = select_debuginfo(matches, &cg, error_format);
2564
2565     let mut search_paths = vec![];
2566     for s in &matches.opt_strs("L") {
2567         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2568     }
2569
2570     let libs = parse_libs(matches, error_format);
2571
2572     let test = matches.opt_present("test");
2573
2574     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2575
2576     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2577         early_warn(
2578             error_format,
2579             "-C remark requires \"-C debuginfo=n\" to show source locations",
2580         );
2581     }
2582
2583     let externs = parse_externs(matches, &debugging_opts, error_format);
2584
2585     let crate_name = matches.opt_str("crate-name");
2586
2587     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2588
2589     let pretty = parse_pretty(matches, &debugging_opts, error_format);
2590
2591     Options {
2592         crate_types,
2593         optimize: opt_level,
2594         debuginfo,
2595         lint_opts,
2596         lint_cap,
2597         describe_lints,
2598         output_types,
2599         search_paths,
2600         maybe_sysroot: sysroot_opt,
2601         target_triple,
2602         test,
2603         incremental,
2604         debugging_opts,
2605         prints,
2606         borrowck_mode,
2607         cg,
2608         error_format,
2609         externs,
2610         crate_name,
2611         alt_std_name: None,
2612         libs,
2613         unstable_features: UnstableFeatures::from_environment(),
2614         debug_assertions,
2615         actually_rustdoc: false,
2616         cli_forced_codegen_units: codegen_units,
2617         cli_forced_thinlto_off: disable_thinlto,
2618         remap_path_prefix,
2619         edition,
2620         json_artifact_notifications,
2621         pretty,
2622     }
2623 }
2624
2625 fn parse_pretty(
2626     matches: &getopts::Matches,
2627     debugging_opts: &DebuggingOptions,
2628     efmt: ErrorOutputType,
2629 ) -> Option<PpMode> {
2630     let pretty = if debugging_opts.unstable_options {
2631         matches.opt_default("pretty", "normal").map(|a| {
2632             // stable pretty-print variants only
2633             parse_pretty_inner(efmt, &a, false)
2634         })
2635     } else {
2636         None
2637     };
2638
2639     return if pretty.is_none() {
2640         debugging_opts.unpretty.as_ref().map(|a| {
2641             // extended with unstable pretty-print variants
2642             parse_pretty_inner(efmt, &a, true)
2643         })
2644     } else {
2645         pretty
2646     };
2647
2648     fn parse_pretty_inner(
2649         efmt: ErrorOutputType,
2650         name: &str,
2651         extended: bool,
2652     ) -> PpMode {
2653         use PpMode::*;
2654         use PpSourceMode::*;
2655         let first = match (name, extended) {
2656             ("normal", _) => PpmSource(PpmNormal),
2657             ("identified", _) => PpmSource(PpmIdentified),
2658             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2659             ("expanded", _) => PpmSource(PpmExpanded),
2660             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2661             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2662             ("hir", true) => PpmHir(PpmNormal),
2663             ("hir,identified", true) => PpmHir(PpmIdentified),
2664             ("hir,typed", true) => PpmHir(PpmTyped),
2665             ("hir-tree", true) => PpmHirTree(PpmNormal),
2666             ("mir", true) => PpmMir,
2667             ("mir-cfg", true) => PpmMirCFG,
2668             _ => {
2669                 if extended {
2670                     early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2671                                         `expanded`, `identified`, `expanded,identified`, \
2672                                         `expanded,hygiene`, `everybody_loops`, \
2673                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2674                                         `mir` or `mir-cfg`; got {}",
2675                                         name));
2676                 } else {
2677                     early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2678                                         `expanded`, `identified`, or `expanded,identified`; got {}",
2679                                         name));
2680                 }
2681             }
2682         };
2683         first
2684     }
2685 }
2686
2687 pub fn make_crate_type_option() -> RustcOptGroup {
2688     opt::multi_s(
2689         "",
2690         "crate-type",
2691         "Comma separated list of types of crates
2692                                 for the compiler to emit",
2693         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2694     )
2695 }
2696
2697 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2698     let mut crate_types: Vec<CrateType> = Vec::new();
2699     for unparsed_crate_type in &list_list {
2700         for part in unparsed_crate_type.split(',') {
2701             let new_part = match part {
2702                 "lib" => default_lib_output(),
2703                 "rlib" => CrateType::Rlib,
2704                 "staticlib" => CrateType::Staticlib,
2705                 "dylib" => CrateType::Dylib,
2706                 "cdylib" => CrateType::Cdylib,
2707                 "bin" => CrateType::Executable,
2708                 "proc-macro" => CrateType::ProcMacro,
2709                 _ => return Err(format!("unknown crate type: `{}`", part))
2710             };
2711             if !crate_types.contains(&new_part) {
2712                 crate_types.push(new_part)
2713             }
2714         }
2715     }
2716
2717     Ok(crate_types)
2718 }
2719
2720 pub mod nightly_options {
2721     use getopts;
2722     use rustc_feature::UnstableFeatures;
2723     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2724     use crate::early_error;
2725
2726     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2727         is_nightly_build()
2728             && matches
2729                 .opt_strs("Z")
2730                 .iter()
2731                 .any(|x| *x == "unstable-options")
2732     }
2733
2734     pub fn is_nightly_build() -> bool {
2735         UnstableFeatures::from_environment().is_nightly_build()
2736     }
2737
2738     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2739         let has_z_unstable_option = matches
2740             .opt_strs("Z")
2741             .iter()
2742             .any(|x| *x == "unstable-options");
2743         let really_allows_unstable_options =
2744             UnstableFeatures::from_environment().is_nightly_build();
2745
2746         for opt in flags.iter() {
2747             if opt.stability == OptionStability::Stable {
2748                 continue;
2749             }
2750             if !matches.opt_present(opt.name) {
2751                 continue;
2752             }
2753             if opt.name != "Z" && !has_z_unstable_option {
2754                 early_error(
2755                     ErrorOutputType::default(),
2756                     &format!(
2757                         "the `-Z unstable-options` flag must also be passed to enable \
2758                          the flag `{}`",
2759                         opt.name
2760                     ),
2761                 );
2762             }
2763             if really_allows_unstable_options {
2764                 continue;
2765             }
2766             match opt.stability {
2767                 OptionStability::Unstable => {
2768                     let msg = format!(
2769                         "the option `{}` is only accepted on the \
2770                          nightly compiler",
2771                         opt.name
2772                     );
2773                     early_error(ErrorOutputType::default(), &msg);
2774                 }
2775                 OptionStability::Stable => {}
2776             }
2777         }
2778     }
2779 }
2780
2781 impl fmt::Display for CrateType {
2782     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2783         match *self {
2784             CrateType::Executable => "bin".fmt(f),
2785             CrateType::Dylib => "dylib".fmt(f),
2786             CrateType::Rlib => "rlib".fmt(f),
2787             CrateType::Staticlib => "staticlib".fmt(f),
2788             CrateType::Cdylib => "cdylib".fmt(f),
2789             CrateType::ProcMacro => "proc-macro".fmt(f),
2790         }
2791     }
2792 }
2793
2794 #[derive(Copy, Clone, PartialEq, Debug)]
2795 pub enum PpSourceMode {
2796     PpmNormal,
2797     PpmEveryBodyLoops,
2798     PpmExpanded,
2799     PpmIdentified,
2800     PpmExpandedIdentified,
2801     PpmExpandedHygiene,
2802     PpmTyped,
2803 }
2804
2805 #[derive(Copy, Clone, PartialEq, Debug)]
2806 pub enum PpMode {
2807     PpmSource(PpSourceMode),
2808     PpmHir(PpSourceMode),
2809     PpmHirTree(PpSourceMode),
2810     PpmMir,
2811     PpmMirCFG,
2812 }
2813
2814 impl PpMode {
2815     pub fn needs_ast_map(&self) -> bool {
2816         use PpMode::*;
2817         use PpSourceMode::*;
2818         match *self {
2819             PpmSource(PpmNormal) |
2820             PpmSource(PpmEveryBodyLoops) |
2821             PpmSource(PpmIdentified) => false,
2822
2823             PpmSource(PpmExpanded) |
2824             PpmSource(PpmExpandedIdentified) |
2825             PpmSource(PpmExpandedHygiene) |
2826             PpmHir(_) |
2827             PpmHirTree(_) |
2828             PpmMir |
2829             PpmMirCFG => true,
2830             PpmSource(PpmTyped) => panic!("invalid state"),
2831         }
2832     }
2833
2834     pub fn needs_analysis(&self) -> bool {
2835         use PpMode::*;
2836         match *self {
2837             PpmMir | PpmMirCFG => true,
2838             _ => false,
2839         }
2840     }
2841 }
2842
2843 /// Command-line arguments passed to the compiler have to be incorporated with
2844 /// the dependency tracking system for incremental compilation. This module
2845 /// provides some utilities to make this more convenient.
2846 ///
2847 /// The values of all command-line arguments that are relevant for dependency
2848 /// tracking are hashed into a single value that determines whether the
2849 /// incremental compilation cache can be re-used or not. This hashing is done
2850 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2851 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2852 /// the hash of which is order dependent, but we might not want the order of
2853 /// arguments to make a difference for the hash).
2854 ///
2855 /// However, since the value provided by `Hash::hash` often *is* suitable,
2856 /// especially for primitive types, there is the
2857 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2858 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2859 /// we have an opt-in scheme here, so one is hopefully forced to think about
2860 /// how the hash should be calculated when adding a new command-line argument.
2861 mod dep_tracking {
2862     use crate::lint;
2863     use crate::utils::NativeLibraryKind;
2864     use std::collections::BTreeMap;
2865     use std::hash::Hash;
2866     use std::path::PathBuf;
2867     use std::collections::hash_map::DefaultHasher;
2868     use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2869                 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2870                 SymbolManglingVersion};
2871     use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2872     use syntax_pos::edition::Edition;
2873     use rustc_feature::UnstableFeatures;
2874
2875     pub trait DepTrackingHash {
2876         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2877     }
2878
2879     macro_rules! impl_dep_tracking_hash_via_hash {
2880         ($t:ty) => (
2881             impl DepTrackingHash for $t {
2882                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2883                     Hash::hash(self, hasher);
2884                 }
2885             }
2886         )
2887     }
2888
2889     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2890         ($t:ty) => (
2891             impl DepTrackingHash for Vec<$t> {
2892                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2893                     let mut elems: Vec<&$t> = self.iter().collect();
2894                     elems.sort();
2895                     Hash::hash(&elems.len(), hasher);
2896                     for (index, elem) in elems.iter().enumerate() {
2897                         Hash::hash(&index, hasher);
2898                         DepTrackingHash::hash(*elem, hasher, error_format);
2899                     }
2900                 }
2901             }
2902         );
2903     }
2904
2905     impl_dep_tracking_hash_via_hash!(bool);
2906     impl_dep_tracking_hash_via_hash!(usize);
2907     impl_dep_tracking_hash_via_hash!(u64);
2908     impl_dep_tracking_hash_via_hash!(String);
2909     impl_dep_tracking_hash_via_hash!(PathBuf);
2910     impl_dep_tracking_hash_via_hash!(lint::Level);
2911     impl_dep_tracking_hash_via_hash!(Option<bool>);
2912     impl_dep_tracking_hash_via_hash!(Option<usize>);
2913     impl_dep_tracking_hash_via_hash!(Option<String>);
2914     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2915     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2916     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2917     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2918     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2919     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2920     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2921     impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2922     impl_dep_tracking_hash_via_hash!(CrateType);
2923     impl_dep_tracking_hash_via_hash!(MergeFunctions);
2924     impl_dep_tracking_hash_via_hash!(PanicStrategy);
2925     impl_dep_tracking_hash_via_hash!(RelroLevel);
2926     impl_dep_tracking_hash_via_hash!(Passes);
2927     impl_dep_tracking_hash_via_hash!(OptLevel);
2928     impl_dep_tracking_hash_via_hash!(LtoCli);
2929     impl_dep_tracking_hash_via_hash!(DebugInfo);
2930     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2931     impl_dep_tracking_hash_via_hash!(OutputTypes);
2932     impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2933     impl_dep_tracking_hash_via_hash!(Sanitizer);
2934     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2935     impl_dep_tracking_hash_via_hash!(TargetTriple);
2936     impl_dep_tracking_hash_via_hash!(Edition);
2937     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2938     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2939     impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2940
2941     impl_dep_tracking_hash_for_sortable_vec_of!(String);
2942     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2943     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2944     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2945     impl_dep_tracking_hash_for_sortable_vec_of!((
2946         String,
2947         Option<String>,
2948         Option<NativeLibraryKind>
2949     ));
2950     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2951     impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2952
2953     impl<T1, T2> DepTrackingHash for (T1, T2)
2954     where
2955         T1: DepTrackingHash,
2956         T2: DepTrackingHash,
2957     {
2958         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2959             Hash::hash(&0, hasher);
2960             DepTrackingHash::hash(&self.0, hasher, error_format);
2961             Hash::hash(&1, hasher);
2962             DepTrackingHash::hash(&self.1, hasher, error_format);
2963         }
2964     }
2965
2966     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2967     where
2968         T1: DepTrackingHash,
2969         T2: DepTrackingHash,
2970         T3: DepTrackingHash,
2971     {
2972         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2973             Hash::hash(&0, hasher);
2974             DepTrackingHash::hash(&self.0, hasher, error_format);
2975             Hash::hash(&1, hasher);
2976             DepTrackingHash::hash(&self.1, hasher, error_format);
2977             Hash::hash(&2, hasher);
2978             DepTrackingHash::hash(&self.2, hasher, error_format);
2979         }
2980     }
2981
2982     // This is a stable hash because BTreeMap is a sorted container
2983     pub fn stable_hash(
2984         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2985         hasher: &mut DefaultHasher,
2986         error_format: ErrorOutputType,
2987     ) {
2988         for (key, sub_hash) in sub_hashes {
2989             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2990             // the keys, as they are just plain strings
2991             Hash::hash(&key.len(), hasher);
2992             Hash::hash(key, hasher);
2993             sub_hash.hash(hasher, error_format);
2994         }
2995     }
2996 }