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