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