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