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