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