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