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