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