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