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