1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command line options.
6 use crate::session::{early_error, early_warn, Session};
7 use crate::session::search_paths::SearchPath;
9 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
10 use rustc_target::spec::{Target, TargetTriple};
12 use crate::middle::cstore;
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;
20 use syntax::symbol::Symbol;
21 use syntax::feature_gate::UnstableFeatures;
22 use errors::emitter::HumanReadableErrorType;
24 use errors::{ColorConfig, FatalError, Handler};
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;
32 use rustc_data_structures::fx::FxHashSet;
34 use std::hash::Hasher;
35 use std::collections::hash_map::DefaultHasher;
36 use std::iter::FromIterator;
37 use std::path::{Path, PathBuf};
45 #[derive(Clone, Hash, Debug)]
53 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
63 impl_stable_hash_via_hash!(OptLevel);
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)]
69 /// Don't do any LTO whatsoever
72 /// Do a full crate graph LTO with ThinLTO
75 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
79 /// Do a full crate graph LTO with "fat" LTO
83 /// The different settings that the `-C lto` flag can have.
84 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
96 /// No `-C lto` flag passed
100 #[derive(Clone, PartialEq, Hash)]
101 pub enum LinkerPluginLto {
102 LinkerPlugin(PathBuf),
107 impl LinkerPluginLto {
108 pub fn enabled(&self) -> bool {
110 LinkerPluginLto::LinkerPlugin(_) |
111 LinkerPluginLto::LinkerPluginAuto => true,
112 LinkerPluginLto::Disabled => false,
117 #[derive(Clone, PartialEq, Hash)]
118 pub enum PgoGenerate {
119 Enabled(Option<PathBuf>),
124 pub fn enabled(&self) -> bool {
126 PgoGenerate::Enabled(_) => true,
127 PgoGenerate::Disabled => false,
132 #[derive(Clone, Copy, PartialEq, Hash)]
139 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
140 pub enum OutputType {
151 impl_stable_hash_via_hash!(OutputType);
154 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
156 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
158 | OutputType::Assembly
159 | OutputType::LlvmAssembly
161 | OutputType::Object => false,
165 fn shorthand(&self) -> &'static str {
167 OutputType::Bitcode => "llvm-bc",
168 OutputType::Assembly => "asm",
169 OutputType::LlvmAssembly => "llvm-ir",
170 OutputType::Mir => "mir",
171 OutputType::Object => "obj",
172 OutputType::Metadata => "metadata",
173 OutputType::Exe => "link",
174 OutputType::DepInfo => "dep-info",
178 fn from_shorthand(shorthand: &str) -> Option<Self> {
179 Some(match shorthand {
180 "asm" => OutputType::Assembly,
181 "llvm-ir" => OutputType::LlvmAssembly,
182 "mir" => OutputType::Mir,
183 "llvm-bc" => OutputType::Bitcode,
184 "obj" => OutputType::Object,
185 "metadata" => OutputType::Metadata,
186 "link" => OutputType::Exe,
187 "dep-info" => OutputType::DepInfo,
192 fn shorthands_display() -> String {
194 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
195 OutputType::Bitcode.shorthand(),
196 OutputType::Assembly.shorthand(),
197 OutputType::LlvmAssembly.shorthand(),
198 OutputType::Mir.shorthand(),
199 OutputType::Object.shorthand(),
200 OutputType::Metadata.shorthand(),
201 OutputType::Exe.shorthand(),
202 OutputType::DepInfo.shorthand(),
206 pub fn extension(&self) -> &'static str {
208 OutputType::Bitcode => "bc",
209 OutputType::Assembly => "s",
210 OutputType::LlvmAssembly => "ll",
211 OutputType::Mir => "mir",
212 OutputType::Object => "o",
213 OutputType::Metadata => "rmeta",
214 OutputType::DepInfo => "d",
215 OutputType::Exe => "",
220 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
221 pub enum ErrorOutputType {
222 HumanReadable(HumanReadableErrorType),
224 /// Render the json in a human readable way (with indents and newlines)
226 /// The way the `rendered` field is created
227 json_rendered: HumanReadableErrorType,
231 impl Default for ErrorOutputType {
232 fn default() -> ErrorOutputType {
233 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
237 // Use tree-based collections to cheaply get a deterministic Hash implementation.
238 // DO NOT switch BTreeMap out for an unsorted container type! That would break
239 // dependency tracking for command-line arguments.
240 #[derive(Clone, Hash)]
241 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
243 impl_stable_hash_via_hash!(OutputTypes);
246 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
247 OutputTypes(BTreeMap::from_iter(
248 entries.iter().map(|&(k, ref v)| (k, v.clone())),
252 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
256 pub fn contains_key(&self, key: &OutputType) -> bool {
257 self.0.contains_key(key)
260 pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
264 pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
268 pub fn len(&self) -> usize {
272 // True if any of the output types require codegen or linking.
273 pub fn should_codegen(&self) -> bool {
274 self.0.keys().any(|k| match *k {
276 | OutputType::Assembly
277 | OutputType::LlvmAssembly
280 | OutputType::Exe => true,
281 OutputType::Metadata | OutputType::DepInfo => false,
286 // Use tree-based collections to cheaply get a deterministic Hash implementation.
287 // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
288 // would break dependency tracking for command-line arguments.
289 #[derive(Clone, Hash)]
290 pub struct Externs(BTreeMap<String, ExternEntry>);
292 #[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
293 pub struct ExternEntry {
294 pub locations: BTreeSet<Option<String>>,
295 pub is_private_dep: bool
299 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
303 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
307 pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, ExternEntry> {
313 macro_rules! hash_option {
314 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
315 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
316 if $sub_hashes.insert(stringify!($opt_name),
317 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
318 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
324 [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
325 if *$opt_expr == $warn_val {
326 early_warn($error_format, $warn_text)
331 macro_rules! top_level_options {
332 (pub struct Options { $(
333 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
341 pub fn dep_tracking_hash(&self) -> u64 {
342 let mut sub_hashes = BTreeMap::new();
347 [$dep_tracking_marker $($warn_val,
349 self.error_format)*]);
351 let mut hasher = DefaultHasher::new();
352 dep_tracking::stable_hash(sub_hashes,
361 // The top-level command-line options struct
363 // For each option, one has to specify how it behaves with regard to the
364 // dependency tracking system of incremental compilation. This is done via the
365 // square-bracketed directive after the field type. The options are:
368 // A change in the given field will cause the compiler to completely clear the
369 // incremental compilation cache before proceeding.
372 // Incremental compilation is not influenced by this option.
374 // [UNTRACKED_WITH_WARNING(val, warning)]
375 // The option is incompatible with incremental compilation in some way. If it
376 // has the value `val`, the string `warning` is emitted as a warning.
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.
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],
400 target_triple: TargetTriple [TRACKED],
402 test: bool [TRACKED],
403 error_format: ErrorOutputType [UNTRACKED],
405 // if Some, enable incremental compilation, using the given
406 // directory to store intermediate results
407 incremental: Option<PathBuf> [UNTRACKED],
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],
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],
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],
437 // Remap source path prefixes in all output (messages, object files, debug, etc)
438 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
440 edition: Edition [TRACKED],
444 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
445 pub enum PrintRequest {
460 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
461 pub enum BorrowckMode {
468 /// Should we run the MIR-based borrow check, but also fall back
469 /// on the AST borrow check if the MIR-based one errors.
470 pub fn migrate(self) -> bool {
472 BorrowckMode::Compare => false,
473 BorrowckMode::Mir => false,
474 BorrowckMode::Migrate => true,
478 /// Should we emit the AST-based borrow checker errors?
479 pub fn use_ast(self) -> bool {
481 BorrowckMode::Compare => true,
482 BorrowckMode::Mir => false,
483 BorrowckMode::Migrate => false,
489 /// Loads source from file
492 /// String that is shown in place of a filename
494 /// Anonymous source string
500 pub fn filestem(&self) -> &str {
502 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
503 Input::Str { .. } => "rust_out",
507 pub fn get_input(&mut self) -> Option<&mut String> {
509 Input::File(_) => None,
510 Input::Str { ref mut input, .. } => Some(input),
514 pub fn source_name(&self) -> FileName {
516 Input::File(ref ifile) => ifile.clone().into(),
517 Input::Str { ref name, .. } => name.clone(),
522 #[derive(Clone, Hash)]
523 pub struct OutputFilenames {
524 pub out_directory: PathBuf,
525 pub out_filestem: String,
526 pub single_output_file: Option<PathBuf>,
528 pub outputs: OutputTypes,
531 impl_stable_hash_via_hash!(OutputFilenames);
533 pub const RUST_CGU_EXT: &str = "rcgu";
535 impl OutputFilenames {
536 pub fn path(&self, flavor: OutputType) -> PathBuf {
539 .and_then(|p| p.to_owned())
540 .or_else(|| self.single_output_file.clone())
541 .unwrap_or_else(|| self.temp_path(flavor, None))
544 /// Gets the path where a compilation artifact of the given type for the
545 /// given codegen unit should be placed on disk. If codegen_unit_name is
546 /// None, a path distinct from those of any codegen unit will be generated.
547 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
548 let extension = flavor.extension();
549 self.temp_path_ext(extension, codegen_unit_name)
552 /// Like temp_path, but also supports things where there is no corresponding
553 /// OutputType, like noopt-bitcode or lto-bitcode.
554 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
555 let base = self.out_directory.join(&self.filestem());
557 let mut extension = String::new();
559 if let Some(codegen_unit_name) = codegen_unit_name {
560 extension.push_str(codegen_unit_name);
564 if !extension.is_empty() {
565 extension.push_str(".");
566 extension.push_str(RUST_CGU_EXT);
567 extension.push_str(".");
570 extension.push_str(ext);
573 let path = base.with_extension(&extension[..]);
577 pub fn with_extension(&self, extension: &str) -> PathBuf {
579 .join(&self.filestem())
580 .with_extension(extension)
583 pub fn filestem(&self) -> String {
584 format!("{}{}", self.out_filestem, self.extra)
588 pub fn host_triple() -> &'static str {
589 // Get the host triple out of the build environment. This ensures that our
590 // idea of the host triple is the same as for the set of libraries we've
591 // actually built. We can't just take LLVM's host triple because they
592 // normalize all ix86 architectures to i386.
594 // Instead of grabbing the host triple (for the current host), we grab (at
595 // compile time) the target triple that this rustc is built with and
596 // calling that (at runtime) the host triple.
597 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
600 impl Default for Options {
601 fn default() -> Options {
603 crate_types: Vec::new(),
604 optimize: OptLevel::No,
605 debuginfo: DebugInfo::None,
606 lint_opts: Vec::new(),
608 describe_lints: false,
609 output_types: OutputTypes(BTreeMap::new()),
610 search_paths: vec![],
612 target_triple: TargetTriple::from_triple(host_triple()),
615 debugging_opts: basic_debugging_options(),
617 borrowck_mode: BorrowckMode::Migrate,
618 cg: basic_codegen_options(),
619 error_format: ErrorOutputType::default(),
620 externs: Externs(BTreeMap::new()),
624 unstable_features: UnstableFeatures::Disallow,
625 debug_assertions: true,
626 actually_rustdoc: false,
627 cli_forced_codegen_units: None,
628 cli_forced_thinlto_off: false,
629 remap_path_prefix: Vec::new(),
630 edition: DEFAULT_EDITION,
636 /// Returns `true` if there is a reason to build the dep graph.
637 pub fn build_dep_graph(&self) -> bool {
638 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
639 || self.debugging_opts.query_dep_graph
643 pub fn enable_dep_node_debug_strs(&self) -> bool {
644 cfg!(debug_assertions)
645 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
648 pub fn file_path_mapping(&self) -> FilePathMapping {
649 FilePathMapping::new(self.remap_path_prefix.clone())
652 /// Returns `true` if there will be an output file generated
653 pub fn will_create_output_file(&self) -> bool {
654 !self.debugging_opts.parse_only && // The file is just being parsed
655 !self.debugging_opts.ls // The file is just being queried
659 pub fn share_generics(&self) -> bool {
660 match self.debugging_opts.share_generics {
661 Some(setting) => setting,
663 match self.optimize {
667 OptLevel::SizeMin => true,
669 OptLevel::Aggressive => false,
676 // The type of entry function, so users can have their own entry functions
677 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
678 pub enum EntryFnType {
683 impl_stable_hash_via_hash!(EntryFnType);
685 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
695 #[derive(Clone, Hash)]
702 pub fn is_empty(&self) -> bool {
704 Passes::Some(ref v) => v.is_empty(),
705 Passes::All => false,
710 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
711 /// at once. The goal of this macro is to define an interface that can be
712 /// programmatically used by the option parser in order to initialize the struct
713 /// without hardcoding field names all over the place.
715 /// The goal is to invoke this macro once with the correct fields, and then this
716 /// macro generates all necessary code. The main gotcha of this macro is the
717 /// cgsetters module which is a bunch of generated code to parse an option into
718 /// its respective field in the struct. There are a few hand-written parsers for
719 /// parsing specific types of values in this module.
720 macro_rules! options {
721 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
722 $buildfn:ident, $prefix:expr, $outputname:expr,
723 $stat:ident, $mod_desc:ident, $mod_set:ident,
724 $($opt:ident : $t:ty = (
727 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
732 pub struct $struct_name { $(pub $opt: $t),* }
734 pub fn $defaultfn() -> $struct_name {
735 $struct_name { $($opt: $init),* }
738 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
740 let mut op = $defaultfn();
741 for option in matches.opt_strs($prefix) {
742 let mut iter = option.splitn(2, '=');
743 let key = iter.next().unwrap();
744 let value = iter.next();
745 let option_to_lookup = key.replace("-", "_");
746 let mut found = false;
747 for &(candidate, setter, opt_type_desc, _) in $stat {
748 if option_to_lookup != candidate { continue }
749 if !setter(&mut op, value) {
750 match (value, opt_type_desc) {
751 (Some(..), None) => {
752 early_error(error_format, &format!("{} option `{}` takes no \
753 value", $outputname, key))
755 (None, Some(type_desc)) => {
756 early_error(error_format, &format!("{0} option `{1}` requires \
757 {2} ({3} {1}=<value>)",
761 (Some(value), Some(type_desc)) => {
762 early_error(error_format, &format!("incorrect value `{}` for {} \
763 option `{}` - {} was expected",
767 (None, None) => bug!()
774 early_error(error_format, &format!("unknown {} option: `{}`",
781 impl<'a> dep_tracking::DepTrackingHash for $struct_name {
782 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
783 let mut sub_hashes = BTreeMap::new();
788 [$dep_tracking_marker $($dep_warn_val,
792 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
796 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
797 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
798 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
800 #[allow(non_upper_case_globals, dead_code)]
802 pub const parse_bool: Option<&str> = None;
803 pub const parse_opt_bool: Option<&str> =
804 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
805 pub const parse_string: Option<&str> = Some("a string");
806 pub const parse_string_push: Option<&str> = Some("a string");
807 pub const parse_pathbuf_push: Option<&str> = Some("a path");
808 pub const parse_opt_string: Option<&str> = Some("a string");
809 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
810 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
811 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
812 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
813 pub const parse_uint: Option<&str> = Some("a number");
814 pub const parse_passes: Option<&str> =
815 Some("a space-separated list of passes, or `all`");
816 pub const parse_opt_uint: Option<&str> =
818 pub const parse_panic_strategy: Option<&str> =
819 Some("either `unwind` or `abort`");
820 pub const parse_relro_level: Option<&str> =
821 Some("one of: `full`, `partial`, or `off`");
822 pub const parse_sanitizer: Option<&str> =
823 Some("one of: `address`, `leak`, `memory` or `thread`");
824 pub const parse_linker_flavor: Option<&str> =
825 Some(::rustc_target::spec::LinkerFlavor::one_of());
826 pub const parse_optimization_fuel: Option<&str> =
827 Some("crate=integer");
828 pub const parse_unpretty: Option<&str> =
829 Some("`string` or `string=string`");
830 pub const parse_treat_err_as_bug: Option<&str> =
831 Some("either no value or a number bigger than 0");
832 pub const parse_lto: Option<&str> =
833 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
835 pub const parse_linker_plugin_lto: Option<&str> =
836 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
837 or the path to the linker plugin");
838 pub const parse_pgo_generate: Option<&str> =
839 Some("an optional path to the profiling data output directory");
840 pub const parse_merge_functions: Option<&str> =
841 Some("one of: `disabled`, `trampolines`, or `aliases`");
846 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate};
847 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
848 use std::path::PathBuf;
849 use std::str::FromStr;
852 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
853 $parse(&mut cg.$opt, v)
857 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
860 None => { *slot = true; true }
864 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
868 "n" | "no" | "off" => {
871 "y" | "yes" | "on" => {
874 _ => { return false; }
879 None => { *slot = Some(true); true }
883 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
885 Some(s) => { *slot = Some(s.to_string()); true },
890 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
892 Some(s) => { *slot = Some(PathBuf::from(s)); true },
897 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
899 Some(s) => { *slot = s.to_string(); true },
904 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
906 Some(s) => { slot.push(s.to_string()); true },
911 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
913 Some(s) => { slot.push(PathBuf::from(s)); true },
918 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
922 slot.extend(s.split_whitespace().map(|s| s.to_string()));
929 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
933 let v = s.split_whitespace().map(|s| s.to_string()).collect();
941 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
945 let v = s.split(',').map(|s| s.to_string()).collect();
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 },
960 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
962 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
963 None => { *slot = None; false }
967 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
974 let mut passes = vec![];
975 if parse_list(&mut passes, v) {
976 *slot = Passes::Some(passes);
985 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
987 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
988 Some("abort") => *slot = Some(PanicStrategy::Abort),
994 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
997 match s.parse::<RelroLevel>() {
998 Ok(level) => *slot = Some(level),
1007 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
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),
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),
1026 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
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()));
1041 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1044 Some(s) if s.split('=').count() <= 2 => {
1045 *slot = Some(s.to_string());
1052 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1054 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1055 None => { *slot = Some(1); true }
1059 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1061 let mut bool_arg = None;
1062 if parse_opt_bool(&mut bool_arg, v) {
1063 *slot = if bool_arg.unwrap() {
1073 None => LtoCli::NoParam,
1074 Some("thin") => LtoCli::Thin,
1075 Some("fat") => LtoCli::Fat,
1076 Some(_) => return false,
1081 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1083 let mut bool_arg = None;
1084 if parse_opt_bool(&mut bool_arg, v) {
1085 *slot = if bool_arg.unwrap() {
1086 LinkerPluginLto::LinkerPluginAuto
1088 LinkerPluginLto::Disabled
1095 None => LinkerPluginLto::LinkerPluginAuto,
1096 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1101 fn parse_pgo_generate(slot: &mut PgoGenerate, v: Option<&str>) -> bool {
1103 None => PgoGenerate::Enabled(None),
1104 Some(path) => PgoGenerate::Enabled(Some(PathBuf::from(path))),
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),
1119 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1120 build_codegen_options, "C", "codegen",
1121 CG_OPTIONS, cg_type_desc, cgsetters,
1122 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1123 "this option is deprecated and does nothing"),
1124 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1125 "system linker to link outputs with"),
1126 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1127 "a single extra argument to append to the linker invocation (can be used several times)"),
1128 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1129 "extra arguments to append to the linker invocation (space separated)"),
1130 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1131 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1132 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1133 "perform LLVM link-time optimizations"),
1134 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1135 "select target processor (rustc --print target-cpus for details)"),
1136 target_feature: String = (String::new(), parse_string, [TRACKED],
1137 "target specific attributes (rustc --print target-features for details)"),
1138 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1139 "a list of extra LLVM passes to run (space separated)"),
1140 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1141 "a list of arguments to pass to llvm (space separated)"),
1142 save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1143 "`-C save-temps` might not produce all requested temporary products \
1144 when incremental compilation is enabled.")],
1145 "save all temporary output files during compilation"),
1146 rpath: bool = (false, parse_bool, [UNTRACKED],
1147 "set rpath values in libs/exes"),
1148 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1149 "use overflow checks for integer arithmetic"),
1150 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1151 "don't pre-populate the pass manager with a list of passes"),
1152 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1153 "don't run the loop vectorization optimization passes"),
1154 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1155 "don't run LLVM's SLP vectorization pass"),
1156 soft_float: bool = (false, parse_bool, [TRACKED],
1157 "use soft float ABI (*eabihf targets only)"),
1158 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1159 "prefer dynamic linking to static linking"),
1160 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1161 "use an external assembler rather than LLVM's integrated one"),
1162 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1163 "disable the use of the redzone"),
1164 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1165 "choose the relocation model to use (rustc --print relocation-models for details)"),
1166 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1167 "choose the code model to use (rustc --print code-models for details)"),
1168 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1169 "metadata to mangle symbol names with"),
1170 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1171 "extra data to put in each output filename"),
1172 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1173 "divide crate into N units to optimize in parallel"),
1174 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1175 "print remarks for these optimization passes (space separated, or \"all\")"),
1176 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1177 "the --no-stack-check flag is deprecated and does nothing"),
1178 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1179 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1180 2 = full debug info with variable and type information"),
1181 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1182 "optimize with possible levels 0-3, s, or z"),
1183 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1184 "force use of the frame pointers"),
1185 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1186 "explicitly enable the cfg(debug_assertions) directive"),
1187 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1188 "set the threshold for inlining a function (default: 225)"),
1189 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1190 [TRACKED], "panic strategy to compile crate with"),
1191 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1192 "enable incremental compilation"),
1193 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1194 "allow the linker to link its default libraries"),
1195 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1197 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1198 parse_linker_plugin_lto, [TRACKED],
1199 "generate build artifacts that are compatible with linker-based LTO."),
1203 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1204 build_debugging_options, "Z", "debugging",
1205 DB_OPTIONS, db_type_desc, dbsetters,
1206 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1207 "the backend to use"),
1208 verbose: bool = (false, parse_bool, [UNTRACKED],
1209 "in general, enable more debug printouts"),
1210 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1211 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1212 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1213 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1214 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1215 "select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
1216 two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
1217 "use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
1218 two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
1219 "when using two-phase-borrows, allow two phases even for non-autoref `&mut` borrows"),
1220 time_passes: bool = (false, parse_bool, [UNTRACKED],
1221 "measure time of each rustc pass"),
1222 time: bool = (false, parse_bool, [UNTRACKED],
1223 "measure time of rustc processes"),
1224 count_llvm_insns: bool = (false, parse_bool,
1225 [UNTRACKED_WITH_WARNING(true,
1226 "The output generated by `-Z count_llvm_insns` might not be reliable \
1227 when used with incremental compilation")],
1228 "count where LLVM instrs originate"),
1229 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1230 "The output of `-Z time-llvm-passes` will only reflect timings of \
1231 re-codegened modules when used with incremental compilation" )],
1232 "measure time of each LLVM pass"),
1233 input_stats: bool = (false, parse_bool, [UNTRACKED],
1234 "gather statistics about the input"),
1235 codegen_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1236 "The output of `-Z codegen-stats` might not be accurate when incremental \
1237 compilation is enabled")],
1238 "gather codegen statistics"),
1239 asm_comments: bool = (false, parse_bool, [TRACKED],
1240 "generate comments into the assembly (may change behavior)"),
1241 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1243 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1244 "gather borrowck statistics"),
1245 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1246 "omit landing pads for unwinding"),
1247 fewer_names: bool = (false, parse_bool, [TRACKED],
1248 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1249 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1250 "gather metadata statistics"),
1251 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1252 "print the arguments passed to the linker"),
1253 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1254 "prints the llvm optimization passes being run"),
1255 ast_json: bool = (false, parse_bool, [UNTRACKED],
1256 "print the AST as JSON and halt"),
1257 threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1258 "use a thread pool with N threads"),
1259 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1260 "print the pre-expansion AST as JSON and halt"),
1261 ls: bool = (false, parse_bool, [UNTRACKED],
1262 "list the symbols defined by a library crate"),
1263 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1264 "write syntax and type analysis (in JSON format) information, in \
1265 addition to normal output"),
1266 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
1267 "include loan analysis data in -Z unpretty flowgraph output"),
1268 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
1269 "include move analysis data in -Z unpretty flowgraph output"),
1270 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
1271 "include assignment analysis data in -Z unpretty flowgraph output"),
1272 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
1273 "include all dataflow analysis data in -Z unpretty flowgraph output"),
1274 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1275 "prints region inference graph. \
1276 Use with RUST_REGION_GRAPH=help for more info"),
1277 parse_only: bool = (false, parse_bool, [UNTRACKED],
1278 "parse only; do not compile, assemble, or link"),
1279 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1280 "load proc macros for both target and host, but only link to the target"),
1281 no_codegen: bool = (false, parse_bool, [TRACKED],
1282 "run all passes except codegen; no output"),
1283 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1284 "treat error number `val` that occurs as bug"),
1285 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1286 "immediately print bugs registered with `delay_span_bug`"),
1287 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1288 "show macro backtraces even for non-local macros"),
1289 teach: bool = (false, parse_bool, [TRACKED],
1290 "show extended diagnostic help"),
1291 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1292 "attempt to recover from parse errors (experimental)"),
1293 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1294 "print tasks that execute and the color their dep node gets (requires debug build)"),
1295 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1296 "enable incremental compilation (experimental)"),
1297 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1298 "enable incremental compilation support for queries (experimental)"),
1299 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1300 "print high-level information about incremental reuse (or the lack thereof)"),
1301 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1302 "dump hash information in textual format to stdout"),
1303 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1304 "verify incr. comp. hashes of green query instances"),
1305 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1306 "ignore spans during ICH computation -- used for testing"),
1307 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1308 "insert function instrument code for mcount-based tracing"),
1309 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1310 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1311 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1312 "enable queries of the dependency graph for regression testing"),
1313 profile_queries: bool = (false, parse_bool, [UNTRACKED],
1314 "trace and profile the queries of the incremental compilation framework"),
1315 profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1316 "trace and profile the queries and keys of the incremental compilation framework"),
1317 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1318 "parse and expand the source, but run no analysis"),
1319 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1320 "load extra plugins"),
1321 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1322 "adds unstable command line options to rustc interface"),
1323 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1324 "force overflow checks on or off"),
1325 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1326 "for every macro invocation, print its name and arguments"),
1327 debug_macros: bool = (false, parse_bool, [TRACKED],
1328 "emit line numbers debug info inside macros"),
1329 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1330 "don't clear the hygiene data after analysis"),
1331 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1332 "keep the AST after lowering it to HIR"),
1333 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1334 "show spans for compiler debugging (expr|pat|ty)"),
1335 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1336 "print layout information for each type encountered"),
1337 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1338 "print the result of the monomorphization collection pass"),
1339 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1340 "set the MIR optimization level (0-3, default: 1)"),
1341 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1342 "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
1343 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1344 "dump MIR state to file.
1345 `val` is used to select which passes and functions to dump. For example:
1346 `all` matches all passes and functions,
1347 `foo` matches all passes for functions whose name contains 'foo',
1348 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1349 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1351 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1352 "the directory the MIR is dumped into"),
1353 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1354 "in addition to `.mir` files, create graphviz `.dot` files"),
1355 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1356 "if set, exclude the pass number when dumping MIR (used in tests)"),
1357 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1358 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1359 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1360 "print some performance-related statistics"),
1361 query_stats: bool = (false, parse_bool, [UNTRACKED],
1362 "print some statistics about the query system"),
1363 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1364 "print some statistics about AST and HIR"),
1365 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1366 "encode MIR of all functions into the crate metadata"),
1367 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1368 "describes how to render the `rendered` field of json diagnostics"),
1369 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1370 "take the breaks off const evaluation. NOTE: this is unsound"),
1371 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1372 "pass `-install_name @rpath/...` to the macOS linker"),
1373 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1375 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1376 "set the optimization fuel quota for a crate"),
1377 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1378 "make Rustc print the total optimization fuel used by a crate"),
1379 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1380 "force all crates to be `rustc_private` unstable"),
1381 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1382 "a single extra argument to prepend the linker invocation (can be used several times)"),
1383 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1384 "extra arguments to prepend to the linker invocation (space separated)"),
1385 profile: bool = (false, parse_bool, [TRACKED],
1386 "insert profiling code"),
1387 pgo_gen: PgoGenerate = (PgoGenerate::Disabled, parse_pgo_generate, [TRACKED],
1388 "Generate PGO profile data, to a given file, or to the default location if it's empty."),
1389 pgo_use: String = (String::new(), parse_string, [TRACKED],
1390 "Use PGO profile data from the given profile file."),
1391 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1392 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1393 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1394 "choose which RELRO level to use"),
1395 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1396 "dump facts from NLL analysis into side files"),
1397 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1398 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1399 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1400 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1401 polonius: bool = (false, parse_bool, [UNTRACKED],
1402 "enable polonius-based borrow-checker"),
1403 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1404 "generate a graphical HTML report of time spent in codegen and LLVM"),
1405 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1406 "enable ThinLTO when possible"),
1407 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1408 "control whether #[inline] functions are in all cgus"),
1409 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1410 "choose the TLS model to use (rustc --print tls-models for details)"),
1411 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1412 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1413 the max/min integer respectively, and NaN is mapped to 0"),
1414 lower_128bit_ops: Option<bool> = (None, parse_opt_bool, [TRACKED],
1415 "rewrite operators on i128 and u128 into lang item calls (typically provided \
1416 by compiler-builtins) so codegen doesn't need to support them,
1417 overriding the default for the current target"),
1418 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1419 "generate human-readable, predictable names for codegen units"),
1420 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1421 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1423 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1424 "Present the input source, unstable (and less-pretty) variants;
1425 valid types are any of the types for `--pretty`, as well as:
1426 `expanded`, `expanded,identified`,
1427 `expanded,hygiene` (with internal representations),
1428 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1429 `flowgraph,unlabelled=<nodeid>` (unlabelled graphviz formatted flowgraph for node),
1430 `everybody_loops` (all function bodies replaced with `loop {}`),
1431 `hir` (the HIR), `hir,identified`,
1432 `hir,typed` (HIR with types for each node),
1433 `hir-tree` (dump the raw HIR),
1434 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1435 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1436 "run `dsymutil` and delete intermediate object files"),
1437 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1438 "format compiler diagnostics in a way that's better suitable for UI testing"),
1439 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1440 "embed LLVM bitcode in object files"),
1441 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1442 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1443 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1444 "make the current crate share its generic instantiations"),
1445 chalk: bool = (false, parse_bool, [TRACKED],
1446 "enable the experimental Chalk-based trait solving engine"),
1447 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1448 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1449 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1450 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1451 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1452 "don't interleave execution of lints; allows benchmarking individual lints"),
1453 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1454 "inject the given attribute in the crate"),
1455 self_profile: bool = (false, parse_bool, [UNTRACKED],
1456 "run the self profiler and output the raw event data"),
1457 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1458 "specifies which kinds of events get recorded by the self profiler"),
1459 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1460 "emits a section containing stack size metadata"),
1461 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1462 "whether to use the PLT when calling into shared libraries;
1463 only has effect for PIC code on systems with ELF binaries
1464 (default: PLT is disabled if full relro is enabled)"),
1465 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1466 "control the operation of the MergeFunctions LLVM pass, taking
1467 the same values as the target option of the same name"),
1468 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1469 "only allow the listed language features to be enabled in code (space separated)"),
1472 pub fn default_lib_output() -> CrateType {
1476 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1477 let end = &sess.target.target.target_endian;
1478 let arch = &sess.target.target.arch;
1479 let wordsz = &sess.target.target.target_pointer_width;
1480 let os = &sess.target.target.target_os;
1481 let env = &sess.target.target.target_env;
1482 let vendor = &sess.target.target.target_vendor;
1483 let min_atomic_width = sess.target.target.min_atomic_width();
1484 let max_atomic_width = sess.target.target.max_atomic_width();
1485 let atomic_cas = sess.target.target.options.atomic_cas;
1487 let mut ret = FxHashSet::default();
1488 ret.reserve(6); // the minimum number of insertions
1490 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1491 if let Some(ref fam) = sess.target.target.options.target_family {
1492 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1493 if fam == "windows" || fam == "unix" {
1494 ret.insert((Symbol::intern(fam), None));
1497 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1498 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1500 Symbol::intern("target_pointer_width"),
1501 Some(Symbol::intern(wordsz)),
1503 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1505 Symbol::intern("target_vendor"),
1506 Some(Symbol::intern(vendor)),
1508 if sess.target.target.options.has_elf_tls {
1509 ret.insert((Symbol::intern("target_thread_local"), None));
1511 for &i in &[8, 16, 32, 64, 128] {
1512 if i >= min_atomic_width && i <= max_atomic_width {
1513 let s = i.to_string();
1515 Symbol::intern("target_has_atomic"),
1516 Some(Symbol::intern(&s)),
1520 Symbol::intern("target_has_atomic"),
1521 Some(Symbol::intern("ptr")),
1527 ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas"))));
1529 if sess.opts.debug_assertions {
1530 ret.insert((Symbol::intern("debug_assertions"), None));
1532 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1533 ret.insert((Symbol::intern("proc_macro"), None));
1538 /// Converts the crate cfg! configuration from String to Symbol.
1539 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1540 /// but the symbol interner is not yet set up then, so we must convert it later.
1541 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1543 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1547 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1548 // Combine the configuration requested by the session (command line) with
1549 // some default and generated configuration items
1550 let default_cfg = default_configuration(sess);
1551 // If the user wants a test runner, then add the test cfg
1553 user_cfg.insert((Symbol::intern("test"), None));
1555 user_cfg.extend(default_cfg.iter().cloned());
1559 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1560 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1561 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1562 .help("Use `--print target-list` for a list of built-in targets")
1567 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1568 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1569 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1570 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1571 w => sp.fatal(&format!(
1572 "target specification was invalid: \
1573 unrecognized target-pointer-width {}",
1585 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1586 pub enum OptionStability {
1591 pub struct RustcOptGroup {
1592 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1593 pub name: &'static str,
1594 pub stability: OptionStability,
1597 impl RustcOptGroup {
1598 pub fn is_stable(&self) -> bool {
1599 self.stability == OptionStability::Stable
1602 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1604 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1609 stability: OptionStability::Stable,
1613 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1615 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1620 stability: OptionStability::Unstable,
1625 // The `opt` local module holds wrappers around the `getopts` API that
1626 // adds extra rustc-specific metadata to each option; such metadata
1627 // is exposed by . The public
1628 // functions below ending with `_u` are the functions that return
1629 // *unstable* options, i.e., options that are only enabled when the
1630 // user also passes the `-Z unstable-options` debugging flag.
1632 // The `fn opt_u` etc below are written so that we can use them
1633 // in the future; do not warn about them not being used right now.
1634 #![allow(dead_code)]
1637 use super::RustcOptGroup;
1639 pub type R = RustcOptGroup;
1640 pub type S = &'static str;
1642 fn stable<F>(name: S, f: F) -> R
1644 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1646 RustcOptGroup::stable(name, f)
1649 fn unstable<F>(name: S, f: F) -> R
1651 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1653 RustcOptGroup::unstable(name, f)
1656 fn longer(a: S, b: S) -> S {
1657 if a.len() > b.len() {
1664 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1665 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1667 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1668 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1670 pub fn flag_s(a: S, b: S, c: S) -> R {
1671 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1673 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1674 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1676 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1677 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1680 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1681 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1683 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1684 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1686 pub fn flag(a: S, b: S, c: S) -> R {
1687 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1689 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1690 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1692 pub fn flagmulti(a: S, b: S, c: S) -> R {
1693 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1697 /// Returns the "short" subset of the rustc command line options,
1698 /// including metadata for each option, such as whether the option is
1699 /// part of the stable long-term interface for rustc.
1700 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1702 opt::flag_s("h", "help", "Display this message"),
1703 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1707 "Add a directory to the library search path. The
1708 optional KIND can be one of dependency, crate, native,
1709 framework or all (the default).",
1715 "Link the generated crate(s) to the specified native
1716 library NAME. The optional KIND can be one of
1717 static, dylib, or framework. If omitted, dylib is
1724 "Comma separated list of types of crates
1725 for the compiler to emit",
1726 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1731 "Specify the name of the crate being built",
1737 "Specify which edition of the compiler to use when compiling code.",
1743 "Comma separated list of types of output for \
1744 the compiler to emit",
1745 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1750 "Comma separated list of compiler information to \
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]",
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"),
1762 "Write output to compiler-chosen filename \
1769 "Provide a detailed explanation of an error \
1773 opt::flag_s("", "test", "Build a test harness"),
1777 "Target triple for which the code is compiled",
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"),
1787 "Set the most restrictive lint level. \
1788 More restrictive lints are capped at this \
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"),
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();
1807 "Specify where an external rust library is located",
1813 "Specify where an extern rust library is located, marking it as a private dependency",
1816 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1817 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1821 "How errors and other messages are produced",
1827 "Choose `rendered` field of json diagnostics render scheme",
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",
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).",
1850 "remap-path-prefix",
1851 "Remap source names in all output (compiler messages and output files)",
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_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());
1866 macro_rules! error {($reason: expr) => {
1867 early_error(ErrorOutputType::default(),
1868 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
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");
1876 match &meta_item.node {
1877 MetaItemKind::List(..) => {
1878 error!(r#"expected `key` or `key="value"`"#);
1880 MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
1881 error!("argument value must be a string");
1883 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
1884 let ident = meta_item.ident().expect("multi-segment cfg key");
1885 return (ident.name, meta_item.value_str());
1890 Err(err) => err.cancel(),
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()))
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;
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;
1912 lint_opts.push((lint_name.replace("-", "_"), level));
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)))
1921 (lint_opts, describe_lints, lint_cap)
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,
1932 None => ColorConfig::Auto,
1934 Some(arg) => early_error(
1935 ErrorOutputType::default(),
1937 "argument for --color must be auto, \
1938 always or never (instead was `{}`)",
1944 let edition = match matches.opt_str("edition") {
1945 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1947 ErrorOutputType::default(),
1949 "argument for --edition must be one of: \
1950 {}. (instead was `{}`)",
1956 None => DEFAULT_EDITION,
1959 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1961 ErrorOutputType::default(),
1963 "Edition {} is unstable and only \
1964 available for nightly builds of rustc.",
1970 let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() {
1972 "termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)),
1974 ErrorOutputType::default(),
1976 "argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)",
1980 }).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never));
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[..]) {
1989 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1990 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1991 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1992 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1994 Some(arg) => early_error(
1995 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1997 "argument for --error-format must be `human`, `json` or \
1998 `short` (instead was `{}`)",
2004 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2007 let unparsed_crate_types = matches.opt_strs("crate-type");
2008 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2009 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2012 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2014 let mut debugging_opts = build_debugging_options(matches, error_format);
2016 if !debugging_opts.unstable_options {
2017 if matches.opt_str("json-rendered").is_some() {
2018 early_error(error_format, "`--json-rendered=x` is unstable");
2020 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2022 ErrorOutputType::Json { pretty: false, json_rendered },
2023 "--error-format=pretty-json is unstable",
2028 if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() {
2031 "options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
2035 let mut output_types = BTreeMap::new();
2036 if !debugging_opts.parse_only {
2037 for list in matches.opt_strs("emit") {
2038 for output_type in list.split(',') {
2039 let mut parts = output_type.splitn(2, '=');
2040 let shorthand = parts.next().unwrap();
2041 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2045 "unknown emission type: `{}` - expected one of: {}",
2047 OutputType::shorthands_display(),
2051 let path = parts.next().map(PathBuf::from);
2052 output_types.insert(output_type, path);
2056 if output_types.is_empty() {
2057 output_types.insert(OutputType::Exe, None);
2060 let mut cg = build_codegen_options(matches, error_format);
2061 let mut codegen_units = cg.codegen_units;
2062 let mut disable_thinlto = false;
2064 // Issue #30063: if user requests llvm-related output to one
2065 // particular path, disable codegen-units.
2066 let incompatible: Vec<_> = output_types
2068 .map(|ot_path| ot_path.0)
2069 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2070 .map(|ot| ot.shorthand())
2072 if !incompatible.is_empty() {
2073 match codegen_units {
2074 Some(n) if n > 1 => {
2075 if matches.opt_present("o") {
2076 for ot in &incompatible {
2080 "--emit={} with -o incompatible with \
2081 -C codegen-units=N for N > 1",
2086 early_warn(error_format, "resetting to default -C codegen-units=1");
2087 codegen_units = Some(1);
2088 disable_thinlto = true;
2092 codegen_units = Some(1);
2093 disable_thinlto = true;
2098 if debugging_opts.threads == Some(0) {
2101 "Value for threads must be a positive nonzero integer",
2105 if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
2108 "Optimization fuel is incompatible with multiple threads",
2112 if codegen_units == Some(0) {
2115 "Value for codegen units must be a positive nonzero integer",
2119 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
2120 (&Some(ref path1), &Some(ref path2)) => {
2125 "conflicting paths for `-Z incremental` and \
2126 `-C incremental` specified: {} versus {}",
2134 (&Some(ref path), &None) => Some(path),
2135 (&None, &Some(ref path)) => Some(path),
2136 (&None, &None) => None,
2137 }.map(|m| PathBuf::from(m));
2139 if debugging_opts.profile && incremental.is_some() {
2142 "can't instrument with gcov profiling when compiling incrementally",
2146 let mut prints = Vec::<PrintRequest>::new();
2147 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2148 prints.push(PrintRequest::TargetCPUs);
2149 cg.target_cpu = None;
2151 if cg.target_feature == "help" {
2152 prints.push(PrintRequest::TargetFeatures);
2153 cg.target_feature = String::new();
2155 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2156 prints.push(PrintRequest::RelocationModels);
2157 cg.relocation_model = None;
2159 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2160 prints.push(PrintRequest::CodeModels);
2161 cg.code_model = None;
2166 .map_or(false, |s| s == "help")
2168 prints.push(PrintRequest::TlsModels);
2169 debugging_opts.tls_model = None;
2174 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2175 let target_triple = if let Some(target) = matches.opt_str("target") {
2176 if target.ends_with(".json") {
2177 let path = Path::new(&target);
2178 TargetTriple::from_path(&path).unwrap_or_else(|_|
2179 early_error(error_format, &format!("target file {:?} does not exist", path)))
2181 TargetTriple::TargetTriple(target)
2184 TargetTriple::from_triple(host_triple())
2187 if matches.opt_present("O") {
2188 if cg.opt_level.is_some() {
2189 early_error(error_format, "-O and -C opt-level both provided");
2193 match cg.opt_level.as_ref().map(String::as_ref) {
2194 None => OptLevel::No,
2195 Some("0") => OptLevel::No,
2196 Some("1") => OptLevel::Less,
2197 Some("2") => OptLevel::Default,
2198 Some("3") => OptLevel::Aggressive,
2199 Some("s") => OptLevel::Size,
2200 Some("z") => OptLevel::SizeMin,
2205 "optimization level needs to be \
2206 between 0-3, s or z (instead was `{}`)",
2214 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2215 let debuginfo = if matches.opt_present("g") {
2216 if cg.debuginfo.is_some() {
2217 early_error(error_format, "-g and -C debuginfo both provided");
2221 match cg.debuginfo {
2222 None | Some(0) => DebugInfo::None,
2223 Some(1) => DebugInfo::Limited,
2224 Some(2) => DebugInfo::Full,
2229 "debug info level needs to be between \
2230 0-2 (instead was `{}`)",
2238 let mut search_paths = vec![];
2239 for s in &matches.opt_strs("L") {
2240 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2247 // Parse string of the form "[KIND=]lib[:new_name]",
2248 // where KIND is one of "dylib", "framework", "static".
2249 let mut parts = s.splitn(2, '=');
2250 let kind = parts.next().unwrap();
2251 let (name, kind) = match (parts.next(), kind) {
2252 (None, name) => (name, None),
2253 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2254 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2255 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2256 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2261 "unknown library kind `{}`, expected \
2262 one of dylib, framework, or static",
2268 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2272 "the library kind 'static-nobundle' is only \
2273 accepted on the nightly compiler"
2277 let mut name_parts = name.splitn(2, ':');
2278 let name = name_parts.next().unwrap();
2279 let new_name = name_parts.next();
2280 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2284 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2285 let test = matches.opt_present("test");
2287 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2289 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2290 "crate-name" => PrintRequest::CrateName,
2291 "file-names" => PrintRequest::FileNames,
2292 "sysroot" => PrintRequest::Sysroot,
2293 "cfg" => PrintRequest::Cfg,
2294 "target-list" => PrintRequest::TargetList,
2295 "target-cpus" => PrintRequest::TargetCPUs,
2296 "target-features" => PrintRequest::TargetFeatures,
2297 "relocation-models" => PrintRequest::RelocationModels,
2298 "code-models" => PrintRequest::CodeModels,
2299 "tls-models" => PrintRequest::TlsModels,
2300 "native-static-libs" => PrintRequest::NativeStaticLibs,
2301 "target-spec-json" => {
2302 if is_unstable_enabled {
2303 PrintRequest::TargetSpec
2307 "the `-Z unstable-options` flag must also be passed to \
2308 enable the target-spec-json print option",
2312 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2315 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2316 None | Some("migrate") => BorrowckMode::Migrate,
2317 Some("mir") => BorrowckMode::Mir,
2318 Some("compare") => BorrowckMode::Compare,
2319 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2322 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2325 "-C remark requires \"-C debuginfo=n\" to show source locations",
2329 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2331 ErrorOutputType::default(),
2332 "'--extern-private' is unstable and only \
2333 available for nightly builds of rustc."
2337 // We start out with a Vec<(Option<String>, bool)>>,
2338 // and later convert it into a BTreeSet<(Option<String>, bool)>
2339 // This allows to modify entries in-place to set their correct
2341 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2342 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2343 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2345 let mut parts = arg.splitn(2, '=');
2346 let name = parts.next().unwrap_or_else(||
2347 early_error(error_format, "--extern value must not be empty"));
2348 let location = parts.next().map(|s| s.to_string());
2349 if location.is_none() && !is_unstable_enabled {
2352 "the `-Z unstable-options` flag must also be passed to \
2353 enable `--extern crate_name` without `=path`",
2358 .entry(name.to_owned())
2362 entry.locations.insert(location.clone());
2364 // Crates start out being not private,
2365 // and go to being private if we see an '--extern-private'
2367 entry.is_private_dep |= private;
2370 let crate_name = matches.opt_str("crate-name");
2372 let remap_path_prefix = matches
2373 .opt_strs("remap-path-prefix")
2376 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2377 let to = parts.next();
2378 let from = parts.next();
2380 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2383 "--remap-path-prefix must contain '=' between FROM and TO",
2392 optimize: opt_level,
2397 output_types: OutputTypes(output_types),
2399 maybe_sysroot: sysroot_opt,
2408 externs: Externs(externs),
2412 unstable_features: UnstableFeatures::from_environment(),
2414 actually_rustdoc: false,
2415 cli_forced_codegen_units: codegen_units,
2416 cli_forced_thinlto_off: disable_thinlto,
2424 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2425 let mut crate_types: Vec<CrateType> = Vec::new();
2426 for unparsed_crate_type in &list_list {
2427 for part in unparsed_crate_type.split(',') {
2428 let new_part = match part {
2429 "lib" => default_lib_output(),
2430 "rlib" => CrateType::Rlib,
2431 "staticlib" => CrateType::Staticlib,
2432 "dylib" => CrateType::Dylib,
2433 "cdylib" => CrateType::Cdylib,
2434 "bin" => CrateType::Executable,
2435 "proc-macro" => CrateType::ProcMacro,
2436 _ => return Err(format!("unknown crate type: `{}`", part))
2438 if !crate_types.contains(&new_part) {
2439 crate_types.push(new_part)
2447 pub mod nightly_options {
2449 use syntax::feature_gate::UnstableFeatures;
2450 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2451 use crate::session::early_error;
2453 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2458 .any(|x| *x == "unstable-options")
2461 pub fn is_nightly_build() -> bool {
2462 UnstableFeatures::from_environment().is_nightly_build()
2465 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2466 let has_z_unstable_option = matches
2469 .any(|x| *x == "unstable-options");
2470 let really_allows_unstable_options =
2471 UnstableFeatures::from_environment().is_nightly_build();
2473 for opt in flags.iter() {
2474 if opt.stability == OptionStability::Stable {
2477 if !matches.opt_present(opt.name) {
2480 if opt.name != "Z" && !has_z_unstable_option {
2482 ErrorOutputType::default(),
2484 "the `-Z unstable-options` flag must also be passed to enable \
2490 if really_allows_unstable_options {
2493 match opt.stability {
2494 OptionStability::Unstable => {
2496 "the option `{}` is only accepted on the \
2500 early_error(ErrorOutputType::default(), &msg);
2502 OptionStability::Stable => {}
2508 impl fmt::Display for CrateType {
2509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2511 CrateType::Executable => "bin".fmt(f),
2512 CrateType::Dylib => "dylib".fmt(f),
2513 CrateType::Rlib => "rlib".fmt(f),
2514 CrateType::Staticlib => "staticlib".fmt(f),
2515 CrateType::Cdylib => "cdylib".fmt(f),
2516 CrateType::ProcMacro => "proc-macro".fmt(f),
2521 /// Command-line arguments passed to the compiler have to be incorporated with
2522 /// the dependency tracking system for incremental compilation. This module
2523 /// provides some utilities to make this more convenient.
2525 /// The values of all command-line arguments that are relevant for dependency
2526 /// tracking are hashed into a single value that determines whether the
2527 /// incremental compilation cache can be re-used or not. This hashing is done
2528 /// via the DepTrackingHash trait defined below, since the standard Hash
2529 /// implementation might not be suitable (e.g., arguments are stored in a Vec,
2530 /// the hash of which is order dependent, but we might not want the order of
2531 /// arguments to make a difference for the hash).
2533 /// However, since the value provided by Hash::hash often *is* suitable,
2534 /// especially for primitive types, there is the
2535 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2536 /// Hash implementation for DepTrackingHash. It's important though that
2537 /// we have an opt-in scheme here, so one is hopefully forced to think about
2538 /// how the hash should be calculated when adding a new command-line argument.
2541 use crate::middle::cstore;
2542 use std::collections::BTreeMap;
2543 use std::hash::Hash;
2544 use std::path::PathBuf;
2545 use std::collections::hash_map::DefaultHasher;
2546 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2547 Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate};
2548 use syntax::feature_gate::UnstableFeatures;
2549 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2550 use syntax::edition::Edition;
2552 pub trait DepTrackingHash {
2553 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2556 macro_rules! impl_dep_tracking_hash_via_hash {
2558 impl DepTrackingHash for $t {
2559 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2560 Hash::hash(self, hasher);
2566 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2568 impl DepTrackingHash for Vec<$t> {
2569 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2570 let mut elems: Vec<&$t> = self.iter().collect();
2572 Hash::hash(&elems.len(), hasher);
2573 for (index, elem) in elems.iter().enumerate() {
2574 Hash::hash(&index, hasher);
2575 DepTrackingHash::hash(*elem, hasher, error_format);
2582 impl_dep_tracking_hash_via_hash!(bool);
2583 impl_dep_tracking_hash_via_hash!(usize);
2584 impl_dep_tracking_hash_via_hash!(u64);
2585 impl_dep_tracking_hash_via_hash!(String);
2586 impl_dep_tracking_hash_via_hash!(PathBuf);
2587 impl_dep_tracking_hash_via_hash!(lint::Level);
2588 impl_dep_tracking_hash_via_hash!(Option<bool>);
2589 impl_dep_tracking_hash_via_hash!(Option<usize>);
2590 impl_dep_tracking_hash_via_hash!(Option<String>);
2591 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2592 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2593 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2594 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2595 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2596 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2597 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2598 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2599 impl_dep_tracking_hash_via_hash!(CrateType);
2600 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2601 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2602 impl_dep_tracking_hash_via_hash!(RelroLevel);
2603 impl_dep_tracking_hash_via_hash!(Passes);
2604 impl_dep_tracking_hash_via_hash!(OptLevel);
2605 impl_dep_tracking_hash_via_hash!(LtoCli);
2606 impl_dep_tracking_hash_via_hash!(DebugInfo);
2607 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2608 impl_dep_tracking_hash_via_hash!(OutputTypes);
2609 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2610 impl_dep_tracking_hash_via_hash!(Sanitizer);
2611 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2612 impl_dep_tracking_hash_via_hash!(TargetTriple);
2613 impl_dep_tracking_hash_via_hash!(Edition);
2614 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2615 impl_dep_tracking_hash_via_hash!(PgoGenerate);
2617 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2618 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2619 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2620 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2621 impl_dep_tracking_hash_for_sortable_vec_of!((
2624 Option<cstore::NativeLibraryKind>
2626 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2628 impl<T1, T2> DepTrackingHash for (T1, T2)
2630 T1: DepTrackingHash,
2631 T2: DepTrackingHash,
2633 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2634 Hash::hash(&0, hasher);
2635 DepTrackingHash::hash(&self.0, hasher, error_format);
2636 Hash::hash(&1, hasher);
2637 DepTrackingHash::hash(&self.1, hasher, error_format);
2641 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2643 T1: DepTrackingHash,
2644 T2: DepTrackingHash,
2645 T3: DepTrackingHash,
2647 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2648 Hash::hash(&0, hasher);
2649 DepTrackingHash::hash(&self.0, hasher, error_format);
2650 Hash::hash(&1, hasher);
2651 DepTrackingHash::hash(&self.1, hasher, error_format);
2652 Hash::hash(&2, hasher);
2653 DepTrackingHash::hash(&self.2, hasher, error_format);
2657 // This is a stable hash because BTreeMap is a sorted container
2659 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2660 hasher: &mut DefaultHasher,
2661 error_format: ErrorOutputType,
2663 for (key, sub_hash) in sub_hashes {
2664 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2665 // the keys, as they are just plain strings
2666 Hash::hash(&key.len(), hasher);
2667 Hash::hash(key, hasher);
2668 sub_hash.hash(hasher, error_format);
2677 use crate::middle::cstore;
2678 use crate::session::config::{
2679 build_configuration,
2680 build_session_options_and_crate_config,
2683 use crate::session::config::{LtoCli, LinkerPluginLto, PgoGenerate, ExternEntry};
2684 use crate::session::build_session;
2685 use crate::session::search_paths::SearchPath;
2686 use std::collections::{BTreeMap, BTreeSet};
2687 use std::iter::FromIterator;
2688 use std::path::PathBuf;
2689 use super::{Externs, OutputType, OutputTypes};
2690 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
2691 use syntax::symbol::Symbol;
2692 use syntax::edition::{Edition, DEFAULT_EDITION};
2697 fn new_public<S: Into<String>,
2698 I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
2699 let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
2704 is_private_dep: false
2709 fn optgroups() -> getopts::Options {
2710 let mut opts = getopts::Options::new();
2711 for group in super::rustc_optgroups() {
2712 (group.apply)(&mut opts);
2717 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2718 BTreeMap::from_iter(entries.into_iter())
2721 // When the user supplies --test we should implicitly supply --cfg test
2723 fn test_switch_implies_cfg_test() {
2724 syntax::with_globals(|| {
2725 let matches = &match optgroups().parse(&["--test".to_string()]) {
2727 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2729 let registry = errors::registry::Registry::new(&[]);
2730 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2731 let sess = build_session(sessopts, None, registry);
2732 let cfg = build_configuration(&sess, to_crate_config(cfg));
2733 assert!(cfg.contains(&(Symbol::intern("test"), None)));
2737 // When the user supplies --test and --cfg test, don't implicitly add
2738 // another --cfg test
2740 fn test_switch_implies_cfg_test_unless_cfg_test() {
2741 syntax::with_globals(|| {
2742 let matches = &match optgroups().parse(&["--test".to_string(),
2743 "--cfg=test".to_string()]) {
2745 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2747 let registry = errors::registry::Registry::new(&[]);
2748 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2749 let sess = build_session(sessopts, None, registry);
2750 let cfg = build_configuration(&sess, to_crate_config(cfg));
2751 let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
2752 assert!(test_items.next().is_some());
2753 assert!(test_items.next().is_none());
2758 fn test_can_print_warnings() {
2759 syntax::with_globals(|| {
2760 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2761 let registry = errors::registry::Registry::new(&[]);
2762 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2763 let sess = build_session(sessopts, None, registry);
2764 assert!(!sess.diagnostic().flags.can_emit_warnings);
2767 syntax::with_globals(|| {
2768 let matches = optgroups()
2769 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
2771 let registry = errors::registry::Registry::new(&[]);
2772 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2773 let sess = build_session(sessopts, None, registry);
2774 assert!(sess.diagnostic().flags.can_emit_warnings);
2777 syntax::with_globals(|| {
2778 let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
2779 let registry = errors::registry::Registry::new(&[]);
2780 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2781 let sess = build_session(sessopts, None, registry);
2782 assert!(sess.diagnostic().flags.can_emit_warnings);
2787 fn test_output_types_tracking_hash_different_paths() {
2788 let mut v1 = Options::default();
2789 let mut v2 = Options::default();
2790 let mut v3 = Options::default();
2793 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2795 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2796 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2798 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2799 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2800 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2803 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2804 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2805 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2809 fn test_output_types_tracking_hash_different_construction_order() {
2810 let mut v1 = Options::default();
2811 let mut v2 = Options::default();
2813 v1.output_types = OutputTypes::new(&[
2814 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2815 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2818 v2.output_types = OutputTypes::new(&[
2819 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2820 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2823 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2826 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2830 fn test_externs_tracking_hash_different_construction_order() {
2831 let mut v1 = Options::default();
2832 let mut v2 = Options::default();
2833 let mut v3 = Options::default();
2835 v1.externs = Externs::new(mk_map(vec![
2838 ExternEntry::new_public(vec![Some("b"), Some("c")])
2842 ExternEntry::new_public(vec![Some("e"), Some("f")])
2846 v2.externs = Externs::new(mk_map(vec![
2849 ExternEntry::new_public(vec![Some("e"), Some("f")])
2853 ExternEntry::new_public(vec![Some("b"), Some("c")])
2857 v3.externs = Externs::new(mk_map(vec![
2860 ExternEntry::new_public(vec![Some("b"), Some("c")])
2864 ExternEntry::new_public(vec![Some("f"), Some("e")])
2868 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2869 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2870 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2873 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2874 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2875 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2879 fn test_lints_tracking_hash_different_values() {
2880 let mut v1 = Options::default();
2881 let mut v2 = Options::default();
2882 let mut v3 = Options::default();
2884 v1.lint_opts = vec![
2885 (String::from("a"), lint::Allow),
2886 (String::from("b"), lint::Warn),
2887 (String::from("c"), lint::Deny),
2888 (String::from("d"), lint::Forbid),
2891 v2.lint_opts = vec![
2892 (String::from("a"), lint::Allow),
2893 (String::from("b"), lint::Warn),
2894 (String::from("X"), lint::Deny),
2895 (String::from("d"), lint::Forbid),
2898 v3.lint_opts = vec![
2899 (String::from("a"), lint::Allow),
2900 (String::from("b"), lint::Warn),
2901 (String::from("c"), lint::Forbid),
2902 (String::from("d"), lint::Deny),
2905 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2906 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2907 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2910 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2911 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2912 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2916 fn test_lints_tracking_hash_different_construction_order() {
2917 let mut v1 = Options::default();
2918 let mut v2 = Options::default();
2920 v1.lint_opts = vec![
2921 (String::from("a"), lint::Allow),
2922 (String::from("b"), lint::Warn),
2923 (String::from("c"), lint::Deny),
2924 (String::from("d"), lint::Forbid),
2927 v2.lint_opts = vec![
2928 (String::from("a"), lint::Allow),
2929 (String::from("c"), lint::Deny),
2930 (String::from("b"), lint::Warn),
2931 (String::from("d"), lint::Forbid),
2934 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2937 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2938 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2942 fn test_search_paths_tracking_hash_different_order() {
2943 let mut v1 = Options::default();
2944 let mut v2 = Options::default();
2945 let mut v3 = Options::default();
2946 let mut v4 = Options::default();
2948 const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
2950 json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
2955 .push(SearchPath::from_cli_opt("native=abc", JSON));
2957 .push(SearchPath::from_cli_opt("crate=def", JSON));
2959 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2961 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2963 .push(SearchPath::from_cli_opt("all=mno", JSON));
2966 .push(SearchPath::from_cli_opt("native=abc", JSON));
2968 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2970 .push(SearchPath::from_cli_opt("crate=def", JSON));
2972 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2974 .push(SearchPath::from_cli_opt("all=mno", JSON));
2977 .push(SearchPath::from_cli_opt("crate=def", JSON));
2979 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2981 .push(SearchPath::from_cli_opt("native=abc", JSON));
2983 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2985 .push(SearchPath::from_cli_opt("all=mno", JSON));
2988 .push(SearchPath::from_cli_opt("all=mno", JSON));
2990 .push(SearchPath::from_cli_opt("native=abc", JSON));
2992 .push(SearchPath::from_cli_opt("crate=def", JSON));
2994 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2996 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2998 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2999 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3000 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
3003 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3004 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3005 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3006 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3010 fn test_native_libs_tracking_hash_different_values() {
3011 let mut v1 = Options::default();
3012 let mut v2 = Options::default();
3013 let mut v3 = Options::default();
3014 let mut v4 = Options::default();
3018 (String::from("a"), None, Some(cstore::NativeStatic)),
3019 (String::from("b"), None, Some(cstore::NativeFramework)),
3020 (String::from("c"), None, Some(cstore::NativeUnknown)),
3025 (String::from("a"), None, Some(cstore::NativeStatic)),
3026 (String::from("X"), None, Some(cstore::NativeFramework)),
3027 (String::from("c"), None, Some(cstore::NativeUnknown)),
3032 (String::from("a"), None, Some(cstore::NativeStatic)),
3033 (String::from("b"), None, Some(cstore::NativeStatic)),
3034 (String::from("c"), None, Some(cstore::NativeUnknown)),
3039 (String::from("a"), None, Some(cstore::NativeStatic)),
3042 Some(String::from("X")),
3043 Some(cstore::NativeFramework),
3045 (String::from("c"), None, Some(cstore::NativeUnknown)),
3048 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
3049 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
3050 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
3053 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3054 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3055 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3056 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3060 fn test_native_libs_tracking_hash_different_order() {
3061 let mut v1 = Options::default();
3062 let mut v2 = Options::default();
3063 let mut v3 = Options::default();
3067 (String::from("a"), None, Some(cstore::NativeStatic)),
3068 (String::from("b"), None, Some(cstore::NativeFramework)),
3069 (String::from("c"), None, Some(cstore::NativeUnknown)),
3073 (String::from("b"), None, Some(cstore::NativeFramework)),
3074 (String::from("a"), None, Some(cstore::NativeStatic)),
3075 (String::from("c"), None, Some(cstore::NativeUnknown)),
3079 (String::from("c"), None, Some(cstore::NativeUnknown)),
3080 (String::from("a"), None, Some(cstore::NativeStatic)),
3081 (String::from("b"), None, Some(cstore::NativeFramework)),
3084 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
3085 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3086 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
3089 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3090 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3091 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3095 fn test_codegen_options_tracking_hash() {
3096 let reference = Options::default();
3097 let mut opts = Options::default();
3099 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3100 opts.cg.ar = Some(String::from("abc"));
3101 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3103 opts.cg.linker = Some(PathBuf::from("linker"));
3104 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3106 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
3107 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3109 opts.cg.link_dead_code = true;
3110 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3112 opts.cg.rpath = true;
3113 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3115 opts.cg.extra_filename = String::from("extra-filename");
3116 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3118 opts.cg.codegen_units = Some(42);
3119 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3121 opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
3122 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3124 opts.cg.save_temps = true;
3125 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3127 opts.cg.incremental = Some(String::from("abc"));
3128 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3130 // Make sure changing a [TRACKED] option changes the hash
3131 opts = reference.clone();
3132 opts.cg.lto = LtoCli::Fat;
3133 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3135 opts = reference.clone();
3136 opts.cg.target_cpu = Some(String::from("abc"));
3137 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3139 opts = reference.clone();
3140 opts.cg.target_feature = String::from("all the features, all of them");
3141 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3143 opts = reference.clone();
3144 opts.cg.passes = vec![String::from("1"), String::from("2")];
3145 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3147 opts = reference.clone();
3148 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
3149 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3151 opts = reference.clone();
3152 opts.cg.overflow_checks = Some(true);
3153 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3155 opts = reference.clone();
3156 opts.cg.no_prepopulate_passes = true;
3157 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3159 opts = reference.clone();
3160 opts.cg.no_vectorize_loops = true;
3161 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3163 opts = reference.clone();
3164 opts.cg.no_vectorize_slp = true;
3165 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3167 opts = reference.clone();
3168 opts.cg.soft_float = true;
3169 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3171 opts = reference.clone();
3172 opts.cg.prefer_dynamic = true;
3173 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3175 opts = reference.clone();
3176 opts.cg.no_integrated_as = true;
3177 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3179 opts = reference.clone();
3180 opts.cg.no_redzone = Some(true);
3181 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3183 opts = reference.clone();
3184 opts.cg.relocation_model = Some(String::from("relocation model"));
3185 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3187 opts = reference.clone();
3188 opts.cg.code_model = Some(String::from("code model"));
3189 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3191 opts = reference.clone();
3192 opts.debugging_opts.tls_model = Some(String::from("tls model"));
3193 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3195 opts = reference.clone();
3196 opts.debugging_opts.pgo_gen = PgoGenerate::Enabled(None);
3197 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3199 opts = reference.clone();
3200 opts.debugging_opts.pgo_use = String::from("abc");
3201 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3203 opts = reference.clone();
3204 opts.cg.metadata = vec![String::from("A"), String::from("B")];
3205 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3207 opts = reference.clone();
3208 opts.cg.debuginfo = Some(0xdeadbeef);
3209 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3211 opts = reference.clone();
3212 opts.cg.debuginfo = Some(0xba5eba11);
3213 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3215 opts = reference.clone();
3216 opts.cg.force_frame_pointers = Some(false);
3217 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3219 opts = reference.clone();
3220 opts.cg.debug_assertions = Some(true);
3221 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3223 opts = reference.clone();
3224 opts.cg.inline_threshold = Some(0xf007ba11);
3225 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3227 opts = reference.clone();
3228 opts.cg.panic = Some(PanicStrategy::Abort);
3229 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3231 opts = reference.clone();
3232 opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
3233 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3237 fn test_debugging_options_tracking_hash() {
3238 let reference = Options::default();
3239 let mut opts = Options::default();
3241 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3242 opts.debugging_opts.verbose = true;
3243 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3244 opts.debugging_opts.time_passes = true;
3245 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3246 opts.debugging_opts.count_llvm_insns = true;
3247 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3248 opts.debugging_opts.time_llvm_passes = true;
3249 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3250 opts.debugging_opts.input_stats = true;
3251 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3252 opts.debugging_opts.codegen_stats = true;
3253 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3254 opts.debugging_opts.borrowck_stats = true;
3255 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3256 opts.debugging_opts.meta_stats = true;
3257 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3258 opts.debugging_opts.print_link_args = true;
3259 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3260 opts.debugging_opts.print_llvm_passes = true;
3261 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3262 opts.debugging_opts.ast_json = true;
3263 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3264 opts.debugging_opts.ast_json_noexpand = true;
3265 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3266 opts.debugging_opts.ls = true;
3267 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3268 opts.debugging_opts.save_analysis = true;
3269 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3270 opts.debugging_opts.flowgraph_print_loans = true;
3271 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3272 opts.debugging_opts.flowgraph_print_moves = true;
3273 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3274 opts.debugging_opts.flowgraph_print_assigns = true;
3275 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3276 opts.debugging_opts.flowgraph_print_all = true;
3277 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3278 opts.debugging_opts.print_region_graph = true;
3279 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3280 opts.debugging_opts.parse_only = true;
3281 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3282 opts.debugging_opts.incremental = Some(String::from("abc"));
3283 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3284 opts.debugging_opts.dump_dep_graph = true;
3285 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3286 opts.debugging_opts.query_dep_graph = true;
3287 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3288 opts.debugging_opts.no_analysis = true;
3289 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3290 opts.debugging_opts.unstable_options = true;
3291 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3292 opts.debugging_opts.trace_macros = true;
3293 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3294 opts.debugging_opts.keep_hygiene_data = true;
3295 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3296 opts.debugging_opts.keep_ast = true;
3297 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3298 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3299 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3300 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3301 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3302 opts.debugging_opts.dump_mir_dir = String::from("abc");
3303 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3304 opts.debugging_opts.dump_mir_graphviz = true;
3305 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3307 // Make sure changing a [TRACKED] option changes the hash
3308 opts = reference.clone();
3309 opts.debugging_opts.asm_comments = true;
3310 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3312 opts = reference.clone();
3313 opts.debugging_opts.verify_llvm_ir = true;
3314 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3316 opts = reference.clone();
3317 opts.debugging_opts.no_landing_pads = true;
3318 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3320 opts = reference.clone();
3321 opts.debugging_opts.fewer_names = true;
3322 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3324 opts = reference.clone();
3325 opts.debugging_opts.no_codegen = true;
3326 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3328 opts = reference.clone();
3329 opts.debugging_opts.treat_err_as_bug = Some(1);
3330 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3332 opts = reference.clone();
3333 opts.debugging_opts.report_delayed_bugs = true;
3334 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3336 opts = reference.clone();
3337 opts.debugging_opts.continue_parse_after_error = true;
3338 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3340 opts = reference.clone();
3341 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3342 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3344 opts = reference.clone();
3345 opts.debugging_opts.force_overflow_checks = Some(true);
3346 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3348 opts = reference.clone();
3349 opts.debugging_opts.show_span = Some(String::from("abc"));
3350 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3352 opts = reference.clone();
3353 opts.debugging_opts.mir_opt_level = 3;
3354 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3356 opts = reference.clone();
3357 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3358 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3360 opts = reference.clone();
3361 opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
3362 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3364 opts = reference.clone();
3365 opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
3366 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3370 fn test_edition_parsing() {
3371 // test default edition
3372 let options = Options::default();
3373 assert!(options.edition == DEFAULT_EDITION);
3375 let matches = optgroups()
3376 .parse(&["--edition=2018".to_string()])
3378 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3379 assert!(sessopts.edition == Edition::Edition2018)