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