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