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